Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(skilavottord): Add municipality #17109

Merged
merged 35 commits into from
Jan 9, 2025
Merged

Conversation

birkirkristmunds
Copy link
Member

@birkirkristmunds birkirkristmunds commented Dec 3, 2024

TS-936

What

Adding CRU for municipality so recycling companies can be put under a municipality
Add new municipality role
Handle what the municipality user with municipality role can do and see

Checklist:

  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • Formatting passes locally with my changes
  • I have rebased against main before asking for a review

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced new roles and permissions for municipalities, enhancing access control.
    • Added new components for managing municipalities, including navigation links and page headers.
    • Implemented new utility functions to streamline partner ID retrieval based on user roles.
    • Created a dedicated module and service for municipalities to manage data effectively.
    • Added new GraphQL queries and mutations to support municipality data operations.
  • Enhancements

    • Updated localization files to support municipality-related features in both English and Icelandic.
    • Improved the AccessControl component to handle dynamic role checks and visibility.
    • Enhanced the RecyclingCompanies component to differentiate between municipalities and recycling companies.
    • Restructured components to utilize new layout elements, improving user interface consistency.
    • Updated the Overview component to reflect the closure of the website with a static message.
  • Bug Fixes

    • Corrected variable names and improved error handling in various services and components.
  • Documentation

    • Updated README to reflect changes in role descriptions and frontend sections.

Copy link
Contributor

coderabbitai bot commented Dec 3, 2024

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 eslint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

warning [email protected]: This version is no longer supported. Please see https://eslint.org/version-support for other options.
warning eslint > @humanwhocodes/[email protected]: Use @eslint/config-array instead
warning eslint > @humanwhocodes/config-array > @humanwhocodes/[email protected]: Use @eslint/object-schema instead
warning eslint > file-entry-cache > flat-cache > [email protected]: Rimraf versions prior to v4 are no longer supported
warning eslint > file-entry-cache > flat-cache > rimraf > [email protected]: Glob versions prior to v9 are no longer supported
warning eslint > file-entry-cache > flat-cache > rimraf > glob > [email protected]: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
warning jest > @jest/core > jest-config > [email protected]: Glob versions prior to v9 are no longer supported
warning jest > @jest/core > jest-runtime > [email protected]: Glob versions prior to v9 are no longer supported
warning jest > @jest/core > @jest/reporters > [email protected]: Glob versions prior to v9 are no longer supported
warning jest > @jest/core > @jest/transform > babel-plugin-istanbul > test-exclude > [email protected]: Glob versions prior to v9 are no longer supported
warning storybook > @storybook/cli > puppeteer-core > [email protected]: Rimraf versions prior to v4 are no longer supported
warning storybook > @storybook/cli > puppeteer-core > rimraf > [email protected]: Glob versions prior to v9 are no longer supported
warning storybook > @storybook/cli > tempy > del > [email protected]: Rimraf versions prior to v4 are no longer supported
warning storybook > @storybook/cli > jscodeshift > @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.
warning storybook > @storybook/cli > jscodeshift > temp > [email protected]: Rimraf versions prior to v4 are no longer supported
warning storybook > @storybook/cli > jscodeshift > temp > rimraf > [email protected]: Glob versions prior to v9 are no longer supported
warning storybook > @storybook/cli > jscodeshift > @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.
warning storybook > @storybook/cli > jscodeshift > @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.
warning react-native > @react-native/codegen > [email protected]: Glob versions prior to v9 are no longer supported
warning react-native > @react-native/community-cli-plugin > [email protected]: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
warning react-native > @react-native-community/cli > @react-native-community/cli-tools > [email protected]: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
warning react-native > @react-native/community-cli-plugin > @react-native/dev-middleware > @rnx-kit/chromium-edge-launcher > [email protected]: Rimraf versions prior to v4 are no longer supported
warning react-native > @react-native/community-cli-plugin > @react-native/metro-babel-transformer > @react-native/babel-preset > @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.
warning react-native > @react-native/community-cli-plugin > @react-native/metro-babel-transformer > @react-native/babel-preset > @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.
warning react-native > @react-native/community-cli-plugin > @react-native/metro-babel-transformer > @react-native/babel-preset > @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.
warning react-native > @react-native/community-cli-plugin > @react-native/metro-babel-transformer > @react-native/babel-preset > @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.
warning react-native > @react-native/community-cli-plugin > @react-native/metro-babel-transformer > @react-native/babel-preset > @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.
warning react-native > @react-native/community-cli-plugin > @react-native/metro-babel-transformer > @react-native/babel-preset > @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead.
warning react-native > @react-native/community-cli-plugin > @react-native/metro-babel-transformer > @react-native/babel-preset > @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.
warning react-native > @react-native/community-cli-plugin > @react-native/metro-babel-transformer > @react-native/babel-preset > @babel/[email protected]: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-logical-assignment-operators instead.
warning next-auth > [email protected]: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
warning next-auth > [email protected]: this version is no longer supported
warning next-auth > @next-auth/typeorm-legacy-adapter > typeorm > [email protected]: Glob versions prior to v9 are no longer supported
warning @nx/next > @nx/webpack > stylus > [email protected]: Glob versions prior to v9 are no longer supported
warning @nx/next > @nx/webpack > webpack-dev-server > [email protected]: Rimraf versions prior to v4 are no longer supported
warning @nx/next > @nx/webpack > fork-ts-checker-webpack-plugin > [email protected]: this will be v4
warning @nx/next > @nx/webpack > webpack-dev-server > webpack-dev-middleware > [email protected]: this will be v4
warning workspace-aggregator-ea1f6067-1b75-4bef-a77d-44f43c3565ff > [email protected]: This version is no longer supported. Please see https://eslint.org/version-support for other options.
warning "@nx/eslint > @nx/js > [email protected]" has unmet peer dependency "@types/node@".
warning "@nx/next > @babel/[email protected]" has unmet peer dependency "@babel/core@^7.0.0-0".
warning "styled-components > babel-plugin-styled-components > @babel/[email protected]" has unmet peer dependency "@babel/core@^7.0.0-0".
warning " > [email protected]" has unmet peer dependency "react-is@>= 16.8.0".
warning "@nx/react > [email protected]" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
warning " > [email protected]" has unmet peer dependency "@types/node@
".
warning " > [email protected]" has incorrect peer dependency "[email protected]".
warning "react-native > @react-native/[email protected]" has unmet peer dependency "@babel/preset-env@^7.1.6".
warning "react-native > @react-native/community-cli-plugin > @react-native/[email protected]" has unmet peer dependency "@babel/core@*".
warning "@vanilla-extract/next-plugin > @vanilla-extract/[email protected]" has unmet peer dependency "webpack@^4.30.0 || ^5.20.2".
warning " > [email protected]" has incorrect peer dependency "react@^16.13.1 || ^17".
warning " > [email protected]" has incorrect peer dependency "react-dom@^16.13.1 || ^17".
warning "next-auth > @next-auth/[email protected]" has unmet peer dependency "@prisma/client@^2.16.1".
warning "@nx/next > [email protected]" has unmet peer dependency "webpack@^5.1.0".

Walkthrough

This pull request introduces a comprehensive update to the Skilavottord application, focusing on adding municipality-related functionality. The changes span multiple components and modules, introducing a new municipality role, updating authorization mechanisms, and enhancing the application's ability to manage recycling partners and access controls. Key modifications include adding new GraphQL models, updating translation files, refactoring authentication utilities, and implementing new routes and components for municipality management.

Changes

File/Group Change Summary
apps/skilavottord/web/auth/utils.ts Removed 'deregisterVehicleKM' from Page type, updated role checking functions, added new functions for municipality and recycling fund roles.
apps/skilavottord/web/components/* Added new components like NavigationLinks, PageHeader, updated Sidenav to include conditional rendering based on roles.
apps/skilavottord/web/i18n/locales/* Updated English and Icelandic translation files with municipality-related keys and modified existing labels for clarity.
apps/skilavottord/ws/src/app/modules/auth/* Added municipality role to the Role enum and updated authorization checks in various services and resolvers.
apps/skilavottord/ws/src/app/modules/recyclingPartner/* Added isMunicipality and municipalityId fields to models and inputs, updated service methods to handle new role-specific logic.
apps/skilavottord/ws/src/app/modules/municipality/* Introduced MunicipalityModule, MunicipalityService, and MunicipalityResolver for managing municipality data.
Backend Resolvers and Services Updated to support municipality-specific queries and permissions, including enhanced error handling and role checks.

Possibly related PRs

Suggested reviewers

  • thordurhhh
  • unakb

Finishing Touches

  • 📝 Generate Docstrings

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

codecov bot commented Dec 3, 2024

Codecov Report

Attention: Patch coverage is 17.75701% with 88 lines in your changes missing coverage. Please review.

Project coverage is 35.65%. Comparing base (af80723) to head (c6e53e7).
Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...ules/recyclingPartner/recyclingPartner.resolver.ts 0.00% 14 Missing ⚠️
...dules/recyclingPartner/recyclingPartner.service.ts 7.14% 13 Missing ⚠️
.../app/modules/municipality/municipality.resolver.ts 0.00% 10 Missing ⚠️
...tord/ws/src/app/modules/vehicle/vehicle.service.ts 28.57% 10 Missing ⚠️
...app/modules/accessControl/accessControl.service.ts 0.00% 9 Missing ⚠️
...c/app/modules/municipality/municipality.service.ts 0.00% 7 Missing ⚠️
...rc/app/modules/municipality/municipality.module.ts 0.00% 6 Missing ⚠️
...pp/modules/accessControl/accessControl.resolver.ts 0.00% 4 Missing ⚠️
apps/skilavottord/ws/src/app/app.module.ts 0.00% 3 Missing ⚠️
...lavottord/ws/src/app/modules/municipality/index.ts 0.00% 2 Missing ⚠️
... and 7 more
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main   #17109      +/-   ##
==========================================
- Coverage   35.66%   35.65%   -0.02%     
==========================================
  Files        6941     6946       +5     
  Lines      149144   149233      +89     
  Branches    42650    42664      +14     
==========================================
+ Hits        53193    53208      +15     
- Misses      95951    96025      +74     
Flag Coverage Δ
web 2.39% <ø> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...c/app/modules/accessControl/accessControl.model.ts 0.00% <ø> (ø)
...skilavottord/ws/src/app/modules/auth/auth.guard.ts 0.00% <ø> (ø)
...modules/recyclingPartner/recyclingPartner.input.ts 100.00% <100.00%> (ø)
...skilavottord/ws/src/app/modules/auth/user.model.ts 0.00% <0.00%> (ø)
apps/skilavottord/ws/src/app/modules/index.ts 0.00% <0.00%> (ø)
...src/app/modules/municipality/municipality.model.ts 83.33% <83.33%> (ø)
...odules/recyclingPartner/recyclingPartner.module.ts 0.00% <0.00%> (ø)
...lavottord/ws/src/app/modules/municipality/index.ts 0.00% <0.00%> (ø)
...modules/recyclingPartner/recyclingPartner.model.ts 84.00% <66.66%> (-1.00%) ⬇️
...dules/recyclingRequest/recyclingRequest.service.ts 8.92% <33.33%> (-0.05%) ⬇️
... and 10 more

... and 1 file with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update af80723...c6e53e7. Read the comment docs.

@datadog-island-is
Copy link

datadog-island-is bot commented Dec 3, 2024

Datadog Report

Branch report: feat/skilavottord-add-municipality
Commit report: d943764
Test service: web

✅ 0 Failed, 84 Passed, 0 Skipped, 25.45s Total Time
➡️ Test Sessions change in coverage: 1 no change

@birkirkristmunds birkirkristmunds marked this pull request as ready for review December 10, 2024 14:44
@birkirkristmunds birkirkristmunds requested a review from a team as a code owner December 10, 2024 14:44
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 20

🧹 Outside diff range and nitpick comments (34)
apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx (5)

7-7: Remove duplicate Option import

The Option type is imported individually and also as part of the destructured import from '@island.is/island-ui/core'.

-import { Box, Button, Option, Select, Stack } from '@island.is/island-ui/core'
+import { Box, Button, Select, Stack } from '@island.is/island-ui/core'

Line range hint 52-56: Clarify the empty onContinue handler

The empty onContinue handler in the Modal component could be confusing. Consider removing it if not needed, as the form submission is handled by the onSubmit prop.

-      onContinue={() => {
-        // Intentionally left empty
-      }}
+      onContinue={undefined}

Line range hint 124-131: Simplify email validation pattern

The current email validation regex is complex and might miss some valid email formats. Consider using a simpler pattern or a dedicated email validation library.

               pattern: {
-                value:
-                  /^[\w!#$%&'*+/=?`{|}~^-]+(?:\.[\w!#$%&'*+/=?`{|}~^-]+)*@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$/i,
+                value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
                 message: t.modal.inputs.email.rules?.validate,
               },

Line range hint 196-207: Improve responsive design implementation

The Box component uses hardcoded padding values which might not scale well across different screen sizes. Consider using theme-based spacing values for better maintainability.

-          <Box paddingX={[3, 3, 3, 15]}></Box>
+          <Box paddingX={[2, 3, 4, 5]}></Box>

Line range hint 30-209: Add loading state handling

The form submission lacks loading state handling, which could lead to multiple submissions. Consider adding a loading state to disable the form during submission.

You could:

  1. Add a loading prop to the component
  2. Disable the submit button and form inputs during submission
  3. Show a loading indicator

Would you like me to provide a detailed implementation?

apps/skilavottord/ws/seeders/20201010211010-seed-recycling-request.js (1)

Line range hint 1-96: Consider adding documentation for test data scenarios

The seeder file contains various test scenarios (different request_types and recycling_partner_id states) but lacks documentation explaining the purpose of each scenario. Consider adding comments to explain:

  1. The significance of null vs non-null recycling_partner_id
  2. The progression of request_types
  3. The relationship between dates and states
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (3)

55-70: Simplify conditional logic for route variables

The logic setting breadcrumbTitle, title, info, activeSection, and route can be simplified for better readability and maintainability.

Consider refactoring as follows:

 const isMunicipality = router.route === routes.municipalities.add

 const {
   t: { recyclingCompanies: t, municipalities: mt, routes },
 } = useI18n()

 const breadcrumbTitle = isMunicipality ? mt.title : t.title
 const title = isMunicipality ? mt.municipality.add.title : t.recyclingCompany.add.title
 const info = isMunicipality ? mt.municipality.add.info : t.recyclingCompany.add.info
 const activeSection = isMunicipality ? 1 : 2
 const route = isMunicipality ? routes.municipalities.baseRoute : routes.recyclingCompanies.baseRoute

117-125: Duplicate code in navigation after creation

The routing logic after a successful creation is duplicated for municipalities and recycling companies.

Refactor to eliminate duplication:

 if (!errors) {
-  if (isMunicipality) {
-    router.push(routes.municipalities.baseRoute).then(() => {
-      toast.success(t.recyclingCompany.add.added)
-    })
-  } else {
-    router.push(routes.recyclingCompanies.baseRoute).then(() => {
-      toast.success(t.recyclingCompany.add.added)
-    })
-  }
+  router.push(route).then(() => {
+    toast.success(t.recyclingCompany.add.added)
+  })
 }

129-135: Simplify handleCancel routing logic

The handleCancel function contains duplicated routing logic based on isMunicipality.

Refactor to use the route variable:

 const handleCancel = () => {
-  if (isMunicipality) {
-    router.push(routes.municipalities.baseRoute)
-  } else {
-    router.push(routes.recyclingCompanies.baseRoute)
-  }
+  router.push(route)
 }
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanies.tsx (2)

59-72: Simplify context-based variables

The variables isMunicipality, buttonText, activeSection, title, and info can be consolidated for clearer logic.

Consider refactoring:

 const isMunicipality = router.route === routes.municipalities.baseRoute

 const buttonText = isMunicipality ? t.buttons.addMunicipality : t.buttons.add
 const activeSection = isMunicipality ? 1 : 2
 const title = isMunicipality ? mt.title : t.title
 const info = isMunicipality ? '' : t.info

101-109: Duplicate code in handleCreate function

The handleCreate function contains duplicated routing logic.

Refactor to use the routes object based on isMunicipality:

 const handleCreate = () => {
   router.push({
-    pathname: isMunicipality ? routes.municipalities.add : routes.recyclingCompanies.add,
+    pathname: route.add,
   })
 }

Ensure you define route similarly to how it's done in other components.

apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (3)

53-57: Avoid unnecessary default assignment

The default assignment || [] is unnecessary when using skip in the query.

Remove the redundant assignment.

 const { data } =
-  useQuery<Query>(SkilavottordAllRecyclingPartnersByTypeQuery, {
+  useQuery<Query>(SkilavottordAllRecyclingPartnersByTypeQuery, {
     skip: isMunicipality,
     variables: { isMunicipality: true },
   })
-  || []

278-311: Conditional rendering might cause layout shift

Conditional rendering of the Select component may cause layout shifts. Consider rendering the component but disabling it or hiding it with CSS to maintain consistent layout.

Alternatively, adjust the layout to accommodate the dynamic content.


374-375: Button icon mismatch

The Button component's icon has been changed to save. Ensure this aligns with the action, and consider using the arrowForward icon for consistency unless saving is appropriate here.

apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (1)

125-147: Unused imports and variables

There are unused imports and variables, such as municipalities, use from 'dd-trace', and potentially others.

Remove unused imports and variables to clean up the code.

apps/skilavottord/web/pages/en/municipalities/index.tsx (1)

1-5: Consider improving type safety and import paths

While the implementation is functional, consider these improvements:

  1. Define the Screen type explicitly on the RecyclingCompanies component instead of using type casting
  2. Consider using path aliases for imports to improve maintainability

Example implementation:

- import { Screen } from '@island.is/skilavottord-web/types'
+ import { Screen } from '@types'
- import { withLocale } from '@island.is/skilavottord-web/i18n'
+ import { withLocale } from '@i18n'
- import { RecyclingCompanies } from '@island.is/skilavottord-web/screens'
+ import { RecyclingCompanies } from '@screens'

- export default withLocale('en')(RecyclingCompanies as Screen)
+ export default withLocale('en')<Screen>(RecyclingCompanies)
apps/skilavottord/web/pages/en/municipalities/add.tsx (1)

1-5: Apply consistent type safety improvements

Similar to the index page, consider improving type safety and import paths:

Example implementation:

- import { Screen } from '@island.is/skilavottord-web/types'
+ import { Screen } from '@types'
- import { withLocale } from '@island.is/skilavottord-web/i18n'
+ import { withLocale } from '@i18n'
- import { RecyclingCompanyCreate } from '@island.is/skilavottord-web/screens/RecyclingCompanies/RecyclingCompanyCreate'
+ import { RecyclingCompanyCreate } from '@screens/RecyclingCompanies/Create'

- export default withLocale('en')(RecyclingCompanyCreate as Screen)
+ export default withLocale('en')<Screen>(RecyclingCompanyCreate)
apps/skilavottord/web/pages/en/municipalities/[id].tsx (1)

1-5: Consider creating a shared page component

The code is identical to the Icelandic version except for the locale parameter. Consider creating a shared page component to reduce duplication:

+ // shared/MunicipalityPage.tsx
+ import { Screen } from '@island.is/skilavottord-web/types'
+ import { withLocale } from '@island.is/skilavottord-web/i18n'
+ import { RecyclingCompanyUpdate } from '@island.is/skilavottord-web/screens/RecyclingCompanies/RecyclingCompanyUpdate'
+
+ export const createMunicipalityPage = (locale: string) =>
+   withLocale(locale)(RecyclingCompanyUpdate as Screen)

Then both locale pages could simply import and use this shared component:

import { createMunicipalityPage } from '../shared/MunicipalityPage'
export default createMunicipalityPage('en') // or 'is'
apps/skilavottord/ws/src/app/modules/auth/user.model.ts (1)

Line range hint 1-28: Consider adding role documentation

The Role enum would benefit from JSDoc comments describing the permissions and responsibilities of each role, especially the newly added municipality role.

 export enum Role {
+  /** System administrator with full access */
   developer = 'developer',
+  /** Company that processes recycled vehicles */
   recyclingCompany = 'recyclingCompany',
+  /** Administrative user for recycling companies */
   recyclingCompanyAdmin = 'recyclingCompanyAdmin',
+  /** Recycling fund administrator */
   recyclingFund = 'recyclingFund',
+  /** Regular user accessing the system */
   citizen = 'citizen',
+  /** Municipality administrator with specific access rights */
   municipality = 'municipality',
 }
apps/skilavottord/web/components/PageHeader/PageHeader.tsx (2)

11-14: Consider enhancing props interface documentation

The props interface could be more descriptive to improve maintainability.

-export const PageHeader: FC<{ title: string; info: string }> = ({
+interface PageHeaderProps {
+  /** Main heading text for the page */
+  title: string;
+  /** Additional information to display in tooltip */
+  info: string;
+}
+
+export const PageHeader: FC<PageHeaderProps> = ({
   title,
   info,
 }) => {

17-26: Consider layout shift optimization

The current order switching between mobile and desktop might cause layout shift during page load.

Consider using CSS Grid's grid-template-areas instead of order properties for a more stable layout that doesn't cause Content Layout Shift (CLS).

apps/skilavottord/web/utils/roleUtils.ts (2)

18-19: Enhance default case handling

The default case using startCase might not be ideal for all future role values.

-    default:
-      return startCase(role)
+    default: {
+      console.warn(`Translation missing for role: ${role}`);
+      return startCase(role);
+    }

Missing test coverage for role translations

The codebase lacks dedicated test coverage for the getRoleTranslation utility function. While there is a test file in the web directory (locales.spec.ts), it doesn't cover the role translations. The function handles critical UI text for different user roles, including the newly added municipality role, and should be properly tested for both Icelandic and English translations.

Suggested actions:

  • Create a new test file roleUtils.spec.ts in apps/skilavottord/web/utils/
  • Add test cases covering all role translations in both languages
  • Include specific test cases for the new municipality role translations ('Sveitarfélag'/'Municipality')
🔗 Analysis chain

Line range hint 6-20: Verify test coverage for new role translation

The new municipality role translation needs test coverage to ensure correct behavior.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for existing test files and their coverage
fd -e test.ts -e spec.ts roleUtils apps/skilavottord/web/utils/

Length of output: 65


Script:

#!/bin/bash
# Let's try a broader search for test files in the web directory
fd -e test.ts -e spec.ts apps/skilavottord/web

# Also search for any usage of getRoleTranslation in test files
rg "getRoleTranslation" -t ts --glob "*test*" --glob "*spec*"

# Search for any test files containing "role" or "Role" to ensure we don't miss any
rg "role|Role" -t ts --glob "*test*" --glob "*spec*" apps/skilavottord/web

Length of output: 577


Script:

#!/bin/bash
# Search for test files in the correct way
fd . apps/skilavottord/web -e test.ts -e spec.ts

# Look for any test files containing Role enum
ast-grep --pattern 'enum Role {
  $$$
}'

# Search for any files importing roleUtils to see test coverage
rg -l "from ['|\"].*roleUtils" 

Length of output: 1261

apps/skilavottord/web/components/NavigationLinks/NavigationLinks.tsx (2)

29-30: Remove unnecessary template literals

Template literals are used unnecessarily for static string values. Since these strings don't contain any interpolation, they can be simplified.

-          title: `${sidenavText.recycled}`,
-          link: `${routes.recycledVehicles}`,
+          title: sidenavText.recycled,
+          link: routes.recycledVehicles,

Apply similar changes to other occurrences.

Also applies to: 34-35, 40-41, 45-46


7-11: Define interface for component props

Consider extracting the props interface for better type documentation and reusability.

+interface NavigationLinksProps {
+  activeSection: number;
+}
+
-export const NavigationLinks = ({
-  activeSection,
-}: {
-  activeSection: number
-}) => {
+export const NavigationLinks = ({ activeSection }: NavigationLinksProps) => {
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.model.ts (2)

108-108: Standardize comment style

The inline comment style differs from the rest of the file. Consider removing it since the @Field decorator with nullable: true is self-documenting.

-  @Field({ nullable: true }) // Ensure this field is nullable in GraphQL
+  @Field({ nullable: true })

101-115: Consider grouping related fields

The new municipality-related fields could be grouped with other identifying fields at the top of the model for better organization.

Consider moving these fields after the companyId field to keep related identifying fields together.

apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts (1)

32-32: Remove redundant comment

The comment restates what's evident from the code and parameter names.

-    // If Role.municipality, return all recycling partners that are not municipalities
apps/skilavottord/ws/src/app/modules/vehicle/vehicle.resolver.ts (1)

21-32: Consider improving role-based filtering logic

While the role-based filtering is functionally correct, the logic could be more explicit and maintainable.

Consider refactoring to:

-  partnerId: user.role === Role.municipality ? user.partnerId : null,
+  partnerId: user.role === Role.municipality 
+    ? user.partnerId 
+    : (user.role === Role.recyclingFund ? null : user.partnerId),

This makes the intent clearer for each role and improves maintainability.

apps/skilavottord/ws/src/app/modules/vehicle/vehicle.service.ts (1)

Line range hint 43-65: Consider implementing pagination optimization

The current implementation might face performance issues with large datasets, especially when filtering across multiple partners.

Consider these optimizations:

  1. Add database indexes for frequently filtered columns
  2. Implement cursor-based pagination instead of offset-based
  3. Consider caching frequently accessed partner relationships
apps/skilavottord/ws/src/app/modules/accessControl/accessControl.resolver.ts (1)

20-25: Consider organizing roles by privilege level

The roles array would be more maintainable if organized by privilege level.

Consider reorganizing roles:

   roles: [
     Role.developer,
     Role.recyclingFund,
+    Role.municipality,
     Role.recyclingCompanyAdmin,
-    Role.municipality,
   ],
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (1)

149-151: Add type validation for municipalityId.

The current type checking could be more robust.

-    if (typeof input.municipalityId !== 'string') {
-      input.municipalityId = input.municipalityId?.value || ''
-    }
+    input.municipalityId = typeof input.municipalityId === 'string' 
+      ? input.municipalityId 
+      : input.municipalityId?.value || ''
apps/skilavottord/web/i18n/locales/is.json (2)

368-372: Ensure consistent navigation structure.

The new municipality-related entries in the sidenav section should maintain hierarchy consistency with other sections.

Consider this structure for better consistency:

  "recyclingFundSidenav": {
    "title": "Úrvinnslusjóður",
-   "municipalityTitle": "Sveitarfélag",
    "recycled": "Meðhöndluð ökutæki",
    "companies": "Móttökuaðilar",
    "accessControl": "Aðgangsstýring",
    "municipalities": "Sveitarfélög"
+   "municipality": {
+     "title": "Sveitarfélag"
+   }
  }

415-425: Improve form field labels and placeholders.

The form input labels and placeholders for company ID and name could be more descriptive.

Consider these improvements:

  "companyId": {
-   "label": "Auðkenni (ID)",
-   "placeholder": "Auðkenni",
+   "label": "Auðkenni fyrirtækis (ID)",
+   "placeholder": "Sláðu inn einkvæmt auðkenni",
    "rules": {
      "required": "Skylda er að fylla út auðkenni"
    }
  },
  "companyName": {
-   "label": "Nafn",
-   "placeholder": "Nafn",
+   "label": "Nafn fyrirtækis",
+   "placeholder": "Sláðu inn nafn fyrirtækis",
    "rules": {
      "required": "Skylda er að fylla út nafn"
    }
  }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 2692a1f and 525e7f7.

📒 Files selected for processing (33)
  • apps/skilavottord/web/auth/utils.ts (1 hunks)
  • apps/skilavottord/web/components/NavigationLinks/NavigationLinks.tsx (1 hunks)
  • apps/skilavottord/web/components/PageHeader/PageHeader.tsx (1 hunks)
  • apps/skilavottord/web/components/Sidenav/Sidenav.tsx (3 hunks)
  • apps/skilavottord/web/i18n/locales/en.json (5 hunks)
  • apps/skilavottord/web/i18n/locales/is.json (5 hunks)
  • apps/skilavottord/web/i18n/locales/translation.d.ts (6 hunks)
  • apps/skilavottord/web/pages/en/municipalities/[id].tsx (1 hunks)
  • apps/skilavottord/web/pages/en/municipalities/add.tsx (1 hunks)
  • apps/skilavottord/web/pages/en/municipalities/index.tsx (1 hunks)
  • apps/skilavottord/web/pages/municipalities/[id].tsx (1 hunks)
  • apps/skilavottord/web/pages/municipalities/add.tsx (1 hunks)
  • apps/skilavottord/web/pages/municipalities/index.tsx (1 hunks)
  • apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (8 hunks)
  • apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx (1 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanies.tsx (3 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (5 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (8 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (5 hunks)
  • apps/skilavottord/web/screens/RecyclingFund/Overview/Overview.tsx (4 hunks)
  • apps/skilavottord/web/utils/roleUtils.ts (1 hunks)
  • apps/skilavottord/ws/migrations/202412013210715-addcolumns-recycling-partners-municipality.js (1 hunks)
  • apps/skilavottord/ws/seeders/20201010211010-seed-recycling-request.js (6 hunks)
  • apps/skilavottord/ws/src/app/modules/accessControl/accessControl.resolver.ts (2 hunks)
  • apps/skilavottord/ws/src/app/modules/accessControl/accessControl.service.ts (2 hunks)
  • apps/skilavottord/ws/src/app/modules/auth/auth.guard.ts (1 hunks)
  • apps/skilavottord/ws/src/app/modules/auth/user.model.ts (1 hunks)
  • apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.input.ts (2 hunks)
  • apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.model.ts (1 hunks)
  • apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts (4 hunks)
  • apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts (2 hunks)
  • apps/skilavottord/ws/src/app/modules/vehicle/vehicle.resolver.ts (1 hunks)
  • apps/skilavottord/ws/src/app/modules/vehicle/vehicle.service.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (33)
apps/skilavottord/web/pages/en/municipalities/index.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/pages/municipalities/index.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/pages/municipalities/[id].tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/pages/en/municipalities/[id].tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/pages/en/municipalities/add.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/components/PageHeader/PageHeader.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/auth/user.model.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/components/NavigationLinks/NavigationLinks.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/accessControl/accessControl.service.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/pages/municipalities/add.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/accessControl/accessControl.resolver.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/migrations/202412013210715-addcolumns-recycling-partners-municipality.js (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.model.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/auth/auth.guard.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/utils/roleUtils.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/components/Sidenav/Sidenav.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/vehicle/vehicle.service.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.input.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanies.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingFund/Overview/Overview.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/seeders/20201010211010-seed-recycling-request.js (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/auth/utils.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/i18n/locales/is.json (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/vehicle/vehicle.resolver.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/i18n/locales/en.json (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/i18n/locales/translation.d.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
🔇 Additional comments (32)
apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx (1)

Line range hint 13-28: Well-structured interface definition

The interface follows TypeScript best practices with proper type safety, clear prop definitions, and appropriate use of generics and utility types.

apps/skilavottord/ws/seeders/20201010211010-seed-recycling-request.js (2)

10-10: Verify the new vehicle ID format against validation rules

The vehicle ID format has been changed from lowercase with hyphens (e.g., 'ftm-522') to uppercase without hyphens (e.g., 'VM006', 'LT579'). Please ensure this new format:

  1. Matches any validation rules in the application
  2. Aligns with the actual vehicle registration number format in Iceland

Also applies to: 19-19, 28-28, 46-46, 55-55, 64-64

✅ Verification successful

Based on the search results, I can see that:

  1. The codebase has both old and new vehicle ID formats:

    • Old format: lowercase with hyphens (e.g., 'jfk-433', 'ftm-522', 'mhs-583')
    • New format: uppercase without hyphens (e.g., 'VM006', 'LT579', 'AE135')
  2. The database schema and indexes support both formats as they use VARCHAR type.

  3. There are no explicit validation rules found for vehicle ID format in the codebase.

Let me generate the final response:

Vehicle ID format change appears safe to proceed

The new uppercase format without hyphens is consistent with other vehicle IDs in the seeder files and is supported by the database schema. No explicit validation rules were found that would conflict with this format change.

  • The database uses VARCHAR type for vehicle_id columns, which accommodates both formats
  • Indexes are format-agnostic: idx_vehicle_id and idx_request_vehicle_id
  • The repeated use of 'AE135' appears intentional for testing scenarios
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for vehicle ID validation patterns in the codebase
rg -g '!*.{json,md,lock}' -i 'vehicle.*validation|vehicle.*pattern|vehicle.*format' 

# Look for any existing vehicle ID usage to confirm format consistency
rg -g '!*/seeders/*' 'vehicle_id.*[A-Z0-9]{2,}' 

Length of output: 43261


28-28: Confirm if repeated vehicle ID 'AE135' is intentional

The vehicle ID 'AE135' is used in three different recycling requests with different states:

  1. Line 28: Default state
  2. Line 46: 'pendingRecycle' state
  3. Line 55: 'handOver' state

This might be intentional for testing different states of the same vehicle, but please verify if this accurately represents your test scenarios.

Also applies to: 46-46, 55-55

✅ Verification successful

Multiple recycling requests for vehicle 'AE135' are intentionally seeded for testing state transitions

Looking at the seeder and migration files, this is a deliberate test data setup:

  • The vehicle 'AE135' exists in the vehicle table (as 'aes-135')
  • The recycling_request table has a foreign key constraint to vehicle table
  • Multiple requests for the same vehicle show the progression through different states:
    1. Default state (initial request)
    2. 'pendingRecycle' state (in progress)
    3. 'handOver' state (completed)

This pattern is also seen with vehicle 'FZG90' which has both 'pendingRecycle' and 'handOver' states, confirming this is an intentional testing pattern.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if multiple requests for the same vehicle are handled in the application
ast-grep --pattern 'function $FUNC($PARAMS) {
  $$$
  vehicle_id
  $$$
}'

Length of output: 75


Script:

#!/bin/bash
# Search for files that handle recycling requests and vehicle IDs
rg -l "vehicle_id" --type js

# Check the content of relevant files for vehicle ID handling
rg "vehicle_id" -A 3 -B 3 --type js

# Look for any unique constraints or validations on vehicle_id
rg "unique.*vehicle_id|vehicle_id.*unique" --type js

Length of output: 15593

apps/skilavottord/web/pages/municipalities/index.tsx (2)

1-3: LGTM! Clean and well-structured imports.

The imports are properly organized using absolute paths, which is good for maintainability.


5-5: 🛠️ Refactor suggestion

⚠️ Potential issue

Component name inconsistency and missing NextJS page structure.

  1. The component name RecyclingCompanies seems inconsistent with the page's purpose (municipalities).
  2. The page lacks proper NextJS structure:
    • Missing static or server-side data fetching methods
    • Missing TypeScript interface for page props
    • Type casting might indicate potential type safety issues

Consider refactoring to follow NextJS best practices:

 import { Screen } from '@island.is/skilavottord-web/types'
 import { withLocale } from '@island.is/skilavottord-web/i18n'
-import { RecyclingCompanies } from '@island.is/skilavottord-web/screens'
+import { Municipalities } from '@island.is/skilavottord-web/screens'
+
+interface MunicipalitiesPageProps {
+  // Add required props here
+}
+
+export const getServerSideProps = async () => {
+  // Fetch required data
+  return {
+    props: {
+      // Return fetched data
+    },
+  }
+}
 
-export default withLocale('is')(RecyclingCompanies as Screen)
+const MunicipalitiesPage: Screen<MunicipalitiesPageProps> = (props) => {
+  return <Municipalities {...props} />
+}
+
+export default withLocale('is')(MunicipalitiesPage)

Let's verify the component naming consistency and type safety:

apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (1)

36-37: Verify server-side handling of new mutation fields

The new fields isMunicipality and municipalityId have been added to the GraphQL mutation. Ensure that the server-side schema and resolvers are updated accordingly to handle these fields.

Run the following script to verify that the server-side schema includes the new fields:

✅ Verification successful

Server-side schema and resolvers are properly updated for new mutation fields

The server-side implementation correctly handles the new fields isMunicipality and municipalityId:

  • The fields are properly defined in the database model (RecyclingPartnerModel)
  • They are included in the mutation input type (CreateRecyclingPartnerInput)
  • The resolver (RecyclingPartnerResolver) is configured to handle these fields in the create mutation
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the server-side GraphQL schema includes 'isMunicipality' and 'municipalityId' in the 'createSkilavottordRecyclingPartner' mutation.

# Fetch the GraphQL schema and search for the fields in the mutation input type.
curl -s http://localhost:3333/api/graphql -H "Content-Type: application/json" \
  -d '{"query": "query { __type(name: \"CreateRecyclingPartnerInput\") { inputFields { name } } }"}' \
  | jq '.data.__type.inputFields[].name' \
  | grep -E 'isMunicipality|municipalityId'

Length of output: 259


Script:

#!/bin/bash
# Let's search for GraphQL schema files and mutations related to recycling partners
fd -e graphql -e gql | xargs cat

# Also search for TypeScript files that might contain the schema definition
rg -l "createSkilavottordRecyclingPartner|CreateRecyclingPartnerInput" --type=typescript

# Search for resolver implementations
ast-grep --pattern 'class $_ {
  $$$
  createSkilavottordRecyclingPartner($_) {
    $$$
  }
  $$$
}'

Length of output: 69739


Script:

#!/bin/bash
# Let's try a different approach to find the schema and resolver files
fd -e ts | xargs rg -l "createSkilavottordRecyclingPartner|CreateRecyclingPartnerInput|isMunicipality|municipalityId"

# Also search for any GraphQL schema files
fd -e graphql | xargs rg "createSkilavottordRecyclingPartner|CreateRecyclingPartnerInput|isMunicipality|municipalityId"

Length of output: 4163


Script:

#!/bin/bash
# Let's examine the relevant files in the skilavottord app
cat apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.model.ts
cat apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.input.ts
cat apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts

Length of output: 6657

apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanies.tsx (1)

80-88: ⚠️ Potential issue

Handle potential undefined user role

When accessing user.role, ensure that user is defined to prevent potential runtime errors.

Apply this diff to add a null check for user:

 const { data, error, loading } = useQuery<Query>(
   SkilavottordAllRecyclingPartnersByTypeQuery,
   {
     variables: {
       isMunicipality,
       municipalityId: partnerId,
     },
+    skip: !user,
   },
 )

Likely invalid or redundant comment.

apps/skilavottord/web/pages/municipalities/add.tsx (1)

1-5: Verify language switching and apply consistent improvements

Similar improvements needed as the English version, plus ensure proper language switching is configured:

Example implementation:

- import { Screen } from '@island.is/skilavottord-web/types'
+ import { Screen } from '@types'
- import { withLocale } from '@island.is/skilavottord-web/i18n'
+ import { withLocale } from '@i18n'
- import { RecyclingCompanyCreate } from '@island.is/skilavottord-web/screens/RecyclingCompanies/RecyclingCompanyCreate'
+ import { RecyclingCompanyCreate } from '@screens/RecyclingCompanies/Create'

- export default withLocale('is')(RecyclingCompanyCreate as Screen)
+ export default withLocale('is')<Screen>(RecyclingCompanyCreate)

Let's verify the language switching configuration:

✅ Verification successful

Language switching is properly configured, but import paths can be improved

The language switching implementation is correctly set up:

  • Both English and Icelandic versions exist with proper locale configuration
  • The withLocale HOC is correctly implemented and used
  • Both versions use the same component with different locale parameters

The suggested import path improvements are valid and can be applied:

  • @island.is/skilavottord-web/types@types
  • @island.is/skilavottord-web/i18n@i18n
  • @island.is/skilavottord-web/screens/RecyclingCompanies/RecyclingCompanyCreate@screens/RecyclingCompanies/Create

The TypeScript generic syntax improvement (withLocale('is')<Screen>(RecyclingCompanyCreate)) is also valid and would provide better type safety.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if language switching is properly configured in next.config.js
echo "Checking Next.js i18n configuration..."
cat next.config.js | grep -A 10 "i18n:"

# Verify that both language versions are properly linked
echo "Checking for language switcher component usage..."
rg -l "LanguageSwitcher" apps/skilavottord/web/

Length of output: 330


Script:

#!/bin/bash
# Let's try to find the Next.js config file with different possible names and locations
echo "Searching for Next.js config files..."
fd -t f "next.config" apps/skilavottord/web/

# Check for i18n configuration in package.json as an alternative
echo "Checking package.json for i18n config..."
fd -t f "package.json" apps/skilavottord/web/ -x cat {} | jq -r '.i18n'

# Let's check for language-related components and configurations
echo "Checking for language-related files..."
rg -l "i18n|locale|language" apps/skilavottord/web/

# Check for the English version of the same page
echo "Checking for English version of municipalities/add..."
fd -t f "add.tsx" apps/skilavottord/web/pages/en/

Length of output: 5243


Script:

#!/bin/bash
# Let's check the Next.js config content for i18n settings
echo "Checking Next.js config content..."
cat apps/skilavottord/web/next.config.js

# Let's examine the i18n implementation
echo "Checking i18n implementation..."
cat apps/skilavottord/web/i18n/withLocale.tsx

# Compare both language versions of the add page
echo "Comparing both language versions..."
echo "=== Icelandic version ==="
cat apps/skilavottord/web/pages/municipalities/add.tsx
echo "=== English version ==="
cat apps/skilavottord/web/pages/en/municipalities/add.tsx

Length of output: 3552

apps/skilavottord/web/pages/municipalities/[id].tsx (1)

1-5: Verify the reuse of RecyclingCompanyUpdate component

While the code follows NextJS conventions, we should verify if reusing the RecyclingCompanyUpdate component for municipalities is intentional and handles municipality-specific requirements correctly.

Additionally, consider adding error boundaries and loading states for better user experience.

✅ Verification successful

Let me gather more information about the RecyclingCompanyUpdate component to verify its usage.


Let me try a different approach to locate and verify the component usage.


Let me check the actual implementation of the RecyclingCompanyUpdate component.


Reuse of RecyclingCompanyUpdate component is intentional and properly implemented

The component is correctly designed to handle both recycling companies and municipalities through the isMunicipality flag. It includes:

  • Proper route detection (router.route === routes.municipalities.edit)
  • Municipality-specific UI adaptations (titles, breadcrumbs, navigation)
  • Correct data handling for municipality role
  • Proper permission checks

The component safely handles both use cases with appropriate conditional logic and type checking. No architectural changes are needed.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if RecyclingCompanyUpdate component handles municipality role
ast-grep --pattern 'interface $_ {
  $$$
  municipality?: $_
  $$$
}'

Length of output: 5527


Script:

#!/bin/bash
# Check RecyclingCompanyUpdate component implementation
ast-grep --pattern 'export const RecyclingCompanyUpdate = $_'

# Search for municipality-related props or types in the component
rg -A 5 "RecyclingCompanyUpdate" apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate.tsx

# Check if there are other municipality-specific components
fd "Municipality" apps/skilavottord/web

Length of output: 328


Script:

#!/bin/bash
# Find all files containing RecyclingCompanyUpdate
rg -l "RecyclingCompanyUpdate"

# Find municipality-related components and pages
fd -e tsx -e ts "municipality" -i

# Check imports in the municipality page
cat apps/skilavottord/web/pages/municipalities/[id].tsx

Length of output: 3650


Script:

#!/bin/bash
# Check the implementation of RecyclingCompanyUpdate component
cat apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx

# Check if there are separate components for municipalities
cat apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/index.tsx

Length of output: 6021

apps/skilavottord/ws/src/app/modules/auth/user.model.ts (1)

9-9: Verify role-based access control implementation

The addition of the municipality role needs careful verification of access control implementation across the application.

✅ Verification successful

Let me gather more specific information about the RBAC implementation.


Let me check the specific roles guard implementation for the skilavottord application.


Role-based access control is properly implemented for the municipality role

The municipality role is correctly integrated into the existing RBAC system:

  • The RolesGuard implementation properly validates user roles
  • The role is used consistently in @authorize decorators alongside other administrative roles (developer, recyclingFund)
  • All recycling partner operations (queries and mutations) properly include the municipality role in their access control
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for proper RBAC implementation for municipality role
echo "Checking resolvers for municipality role authorization..."
rg -l "Role.municipality" --type ts

echo "\nChecking guards and decorators..."
ast-grep --pattern '@$_($$$)
export class $_ {
  $$$
  @$_([Role.municipality])
  $$$
}'

Length of output: 1081


Script:

#!/bin/bash
# Check resolver implementations for municipality role
echo "Checking vehicle resolver implementation..."
rg -B 2 -A 5 "Role\.municipality" apps/skilavortord/ws/src/app/modules/vehicle/vehicle.resolver.ts

echo "\nChecking access control resolver implementation..."
rg -B 2 -A 5 "Role\.municipality" apps/skilavortord/ws/src/app/modules/accessControl/accessControl.resolver.ts

echo "\nChecking for role-based guards..."
rg -l "RolesGuard" --type ts

echo "\nChecking guard implementations..."
ast-grep --pattern 'class $_ implements CanActivate {
  $$$
  canActivate($$$) {
    $$$
  }
}'

Length of output: 9011


Script:

#!/bin/bash
# Check roles guard implementation in skilavottord
echo "Checking roles guard implementation..."
rg -B 2 -A 10 "class RolesGuard" apps/skilavottord/ws/src/app/modules/auth/roles.guard.ts

echo "\nChecking for roles decorator usage..."
rg -B 2 -A 5 "@Roles" apps/skilavottord/ws/src/app/modules/

echo "\nChecking recycling partner resolver for role checks..."
rg -B 2 -A 5 "Role\.municipality" apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts

Length of output: 2185

apps/skilavottord/ws/migrations/202412013210715-addcolumns-recycling-partners-municipality.js (1)

4-10: Consider adding foreign key constraint

The municipality_id column appears to reference municipalities but lacks a foreign key constraint.

Consider adding a foreign key constraint to ensure referential integrity:

ALTER TABLE recycling_partner 
ADD CONSTRAINT fk_recycling_partner_municipality 
FOREIGN KEY (municipality_id) 
REFERENCES municipality(id);

Let's verify if the municipality table exists:

apps/skilavottord/web/auth/utils.ts (3)

21-28: LGTM: Permission updates for recycling company roles

The removal of 'deregisterVehicleKM' from recycling company roles while maintaining essential permissions follows the principle of least privilege.


34-34: LGTM: New municipality role with appropriate permissions

The new municipality role has been granted appropriate permissions for viewing recycled vehicles, recycling companies, and access control.


28-34: Verify the impact of adding 'municipalities' permission

The addition of 'municipalities' to recyclingFund role's permissions needs verification to ensure all related UI components handle this new permission correctly.

✅ Verification successful

The addition of 'municipalities' permission is properly handled in the codebase

The codebase already has comprehensive support for the 'municipalities' permission:

  • The permission is correctly added to the recyclingFund role in auth/utils.ts
  • The UI components handling municipalities are properly implemented with permission checks:
    • Navigation links in NavigationLinks.tsx handle municipality-related routes
    • Dedicated screens for municipalities exist with proper permission checks
    • Form components in RecyclingCompanyForm handle municipality-specific fields
    • Role-based access control is implemented throughout the codebase
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for UI components that might need updates for the new 'municipalities' permission
rg -t tsx -t ts "municipalities" apps/skilavottord/web/

Length of output: 83


Script:

#!/bin/bash
# Search for UI components that might need updates for the new 'municipalities' permission
# Using ripgrep without file type restrictions and checking the entire web directory
rg "municipalities" apps/skilavottord/web/

# Also search for any components or code handling permissions
rg -A 3 "hasPermission|usePermissions" apps/skilavottord/web/

# Check for any routes or components related to municipalities
rg -i "municipality|municipalities" apps/skilavottord/web/

Length of output: 29796

apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.input.ts (1)

44-45: LGTM: Nullable configuration for municipalityId

The municipalityId field is correctly configured as nullable in both the decorator and type.

apps/skilavottord/web/components/Sidenav/Sidenav.tsx (3)

3-7: LGTM: Clean interface extension

The addition of the optional hidden property to SidenavSection interface follows TypeScript best practices.


16-16: LGTM: Type extension for municipality icon

The SidenavIcon type has been correctly extended to include the new municipality icon.


26-26: LGTM: Clean conditional rendering

The section rendering logic has been updated to handle the new hidden property while maintaining readability.

apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts (1)

28-52: Verify the handling of null values

The current implementation might need additional validation for edge cases.

✅ Verification successful

Null handling is properly implemented in the codebase

The code correctly handles null values for both isMunicipality and municipalityId fields:

  • The model definition explicitly marks municipalityId as nullable with allowNull: true
  • The GraphQL schema properly defines nullable fields with @Field({ nullable: true })
  • The service method correctly handles the OR condition for isMunicipality: null
  • The resolver properly defines nullable arguments with nullable: true
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential null handling issues in the codebase

# Check for explicit null checks in similar service methods
rg -A 2 "findAll.*null" apps/skilavottord/ws/src/app/modules

# Check for related model validations
ast-grep --pattern 'allowNull: true' apps/skilavottord/ws/src/app/modules

Length of output: 138


Script:

#!/bin/bash
# Let's check the model definition and related files for null handling

# Find the recycling partner model definition
fd "recyclingPartner.*model" apps/skilavottord/ws/src

# Check for null handling in the model and related files
rg -g "*.ts" "isMunicipality.*null|municipalityId.*null" apps/skilavottord/ws/src/app/modules

# Check for any validation or type definitions
rg -g "*.ts" "interface.*RecyclingPartner|type.*RecyclingPartner" apps/skilavottord/ws/src

Length of output: 1598


Script:

#!/bin/bash
# Let's examine the model definition and input types

# Check the model definition
cat apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.model.ts

# Check the input types
rg -g "*.ts" -A 5 "RecyclingPartnerInput|CreateRecyclingPartnerInput|UpdateRecyclingPartnerInput" apps/skilavottord/ws/src/app/modules/recyclingPartner/

Length of output: 10114

apps/skilavottord/ws/src/app/modules/auth/auth.guard.ts (1)

80-80: ⚠️ Potential issue

Verify security implications of removing IdsUserGuard

The removal of IdsUserGuard from the UseGuards decorator could potentially impact authentication security. Please ensure this change aligns with the application's security requirements.

Consider keeping IdsUserGuard for additional security layer or document why it's safe to remove.

apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts (1)

20-20: Verify role-based access control implementation

The addition of Role.municipality to multiple methods needs verification:

  1. Ensure proper access restrictions
  2. Verify that municipality users can only access their own data

Also applies to: 55-55, 66-66, 87-87

✅ Verification successful

Let me gather more information about the access control implementation specific to municipality role.


Let me check the recycling partner service implementation to understand how municipality data access is restricted.


Role-based access control is properly implemented for municipality users

The codebase shows appropriate access restrictions for municipality users:

  • Municipality users can only access recycling partners that are not municipalities and belong to their municipality (filtered by municipalityId)
  • Vehicle queries are restricted by partnerId when the user has municipality role
  • The @authorize decorator properly enforces role-based access across resolvers
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for role checks in the codebase
rg "Role\.municipality" --type ts

# Look for access control implementations
ast-grep --pattern 'class $_ implements CanActivate {
  $$$
  canActivate($_) {
    $$$
  }
}'

Length of output: 4745


Script:

#!/bin/bash
# Check how municipality access is restricted in services
rg "Role\.municipality.*partnerId" -A 5 --type ts

# Look for partnerId checks in resolvers
ast-grep --pattern 'if ($user.role === Role.municipality) {
  $$$
}'

# Check authorization decorator implementation
rg "@Authorize" -A 3 --type ts

Length of output: 9492


Script:

#!/bin/bash
# Check recycling partner service implementation
rg -A 10 "class RecyclingPartnerService" --type ts

# Look for municipality-specific filtering in the service
rg -A 10 "Role\.municipality.*return" --type ts

# Check how partnerId is used in queries
ast-grep --pattern 'findOne({
  $$$
  partnerId: $user.partnerId
  $$$
})'

Length of output: 2637

apps/skilavottord/ws/src/app/modules/vehicle/vehicle.resolver.ts (1)

Line range hint 1-24: Verify access control implications of new municipality role

The addition of the municipality role requires verification of access control boundaries.

✅ Verification successful

Let me gather more information about the authorization patterns in the codebase.


Municipality role access control implementation is properly bounded

The municipality role has been consistently implemented with appropriate access controls across the codebase:

  • Access to skilavottordAllDeregisteredVehicles is properly restricted to [Role.developer, Role.recyclingFund, Role.municipality]
  • Municipality role access is limited to specific endpoints in recycling partner operations
  • The role's access is properly filtered using partnerId when querying vehicle data
  • No security implications found as the role follows the same authorization patterns as other roles in the system
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for potential security implications of municipality role
# Look for other endpoints that might need municipality role

# Search for @Authorize decorators
rg -B 2 -A 2 "@Authorize\({" 

# Search for role-based checks
rg "user\.role === " 

Length of output: 4935


Script:

#!/bin/bash
# Search for Authorize decorators with better regex
rg "@Authorize\(" -A 2

# Search for municipality role usage
rg "Role\.municipality"

# Search for role-based mutations/queries in vehicle resolver
ast-grep --pattern $'@Authorize({ roles: [$$$] })
@$_($$$) $$$'

Length of output: 9010

apps/skilavottord/web/screens/RecyclingFund/Overview/Overview.tsx (2)

27-28: LGTM: Component modernization improves maintainability.

The replacement of Sidenav with NavigationLinks and Box with PageHeader aligns with modern component architecture, improving code maintainability and reusability.

Also applies to: 121-121, 141-141


31-36: Verify the impact of the required municipalityId parameter.

The GraphQL query now requires a municipalityId parameter. This change could affect existing query implementations.

apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (2)

122-124: 🛠️ Refactor suggestion

Consider using useEffect dependency array properly.

The useEffect hook should include all dependencies it uses.

-  React.useEffect(() => {
-    setValue('isMunicipality', isMunicipality)
-  }, [isMunicipality, setValue])
+  React.useEffect(() => {
+    setValue('isMunicipality', isMunicipality)
+  }, [isMunicipality, setValue])

Likely invalid or redundant comment.


81-87: Verify role-based access control for municipality users.

The component now handles municipality-specific logic. Ensure proper access control is maintained.

✅ Verification successful

Let me analyze the role-based access control implementation for municipality users based on the search results. I can see comprehensive evidence of proper RBAC implementation across the codebase, but let me verify the specific authorization checks for recycling company operations.


Role-based access control for municipality users is properly implemented

The verification shows comprehensive and consistent RBAC implementation:

  • Backend authorization is properly enforced through @Authorize decorators that explicitly include Role.municipality for relevant recycling partner operations
  • Frontend components correctly handle municipality-specific logic by:
    • Filtering recycling companies based on partnerId
    • Implementing proper role checks before rendering components
    • Maintaining proper access control in navigation and views

The implementation in RecyclingCompanyUpdate.tsx aligns with the overall RBAC architecture of the system.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for proper role definitions and access control
rg -A 5 "Role.municipality"

Length of output: 12054


Script:

#!/bin/bash
# Check for authorization decorators and role checks in recycling partner related files
ast-grep --pattern 'Authorize({ roles: [$$$] })'

Length of output: 5015

apps/skilavottord/web/i18n/locales/en.json (1)

638-642: LGTM: Well-structured route definitions.

The new municipality routes are properly structured and consistent with existing patterns.

apps/skilavottord/web/i18n/locales/translation.d.ts (5)

33-33: LGTM! Proper type definition for municipalities.

The municipalities property is correctly added to the Translation interface.


477-492: LGTM! Well-structured municipality interfaces.

The Municipalities and Municipality interfaces are properly defined with all necessary properties and follow the existing pattern.


517-517: LGTM! Optional municipality field in form inputs.

The municipality field is correctly added to the FormInputs interface as an optional field.


560-564: LGTM! Proper sidenav type definitions.

The municipalityTitle and municipalities properties are correctly added to the RecyclingFundSidenav interface.


577-577: LGTM! Route type definition for municipalities.

The municipalities property is correctly added to the Routes interface using the existing RecyclingCompaniesClass type.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Outside diff range and nitpick comments (8)
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (3)

84-90: Consider a more robust route check

The current route check for isMunicipality is tightly coupled to the exact route path. Consider using a more maintainable approach.

Consider this alternative:

- const isMunicipality = router.route === routes.municipalities.edit
+ const isMunicipality = router.route.startsWith(routes.municipalities.baseRoute)

119-124: Move string literals to translation constants

Consider moving the hardcoded section number and route to translation constants for better maintainability.

Example approach:

const SECTIONS = {
  RECYCLING_COMPANIES: 2,
  MUNICIPALITIES: 1,
} as const

Line range hint 156-164: Enhance error handling in mutation response

The current error handling doesn't provide user feedback when the mutation fails.

Add error handling:

  const { errors } = await updateSkilavottordRecyclingPartner({
    variables: { input },
  })
  if (!errors) {
    router.push(routes.recyclingCompanies.baseRoute).then(() => {
      toast.success(t.recyclingCompany.view.updated)
    })
+ } else {
+   toast.error(t.recyclingCompany.view.updateError)
  }
🧰 Tools
🪛 Biome (1.9.4)

[error] 150-150: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

apps/skilavottord/web/components/NavigationLinks/NavigationLinks.tsx (2)

12-21: Consider adding null safety to role check

The role check could be made more robust by adding null safety:

-  if (hasMunicipalityRole(user?.role)) {
+  if (user?.role && hasMunicipalityRole(user.role)) {

23-52: Remove unnecessary template literals

Template literals are used unnecessarily for static strings in the sections array.

-          title: `${sidenavText.recycled}`,
-          link: `${routes.recycledVehicles}`,
+          title: sidenavText.recycled,
+          link: routes.recycledVehicles,
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (1)

58-73: Consider extracting route comparison logic

The route comparison could be made more maintainable by using a constant.

+const MUNICIPALITY_ROUTE = routes.municipalities.add;
+
-const isMunicipality = router.route === routes.municipalities.add
+const isMunicipality = router.route === MUNICIPALITY_ROUTE
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (2)

123-145: Consolidate data fetching logic for recycling partners

The current implementation uses two separate useLazyQuery hooks (getAllRecyclingPartner and getAllRecyclingPartnersByMunicipality) to fetch recycling partner data based on the user's role. This can be simplified by combining the logic into a single hook or function that handles the condition internally. This will reduce code duplication and improve maintainability.

Consider refactoring as follows:

- const [
-   getAllRecyclingPartner,
-   {
-     data: recyclingPartnerData,
-     error: recyclingPartnerError,
-     loading: recyclingPartnerLoading,
-   },
- ] = useLazyQuery<Query>(SkilavottordAllRecyclingPartnersQuery, {
-   ssr: false,
- })
- 
- const [
-   getAllRecyclingPartnersByMunicipality,
-   {
-     data: recyclingPartnerByIdData,
-     error: recyclingPartnerByIdError,
-     loading: recyclingPartnerByIdLoading,
-   },
- ] = useLazyQuery<Query>(SkilavottordAllRecyclingPartnersByTypeQuery, {
-   ssr: false,
-   variables: { isMunicipality: false, municipalityId: user?.partnerId },
- })
+ const [
+   getRecyclingPartners,
+   {
+     data: recyclingPartnerData,
+     error: recyclingPartnerError,
+     loading: recyclingPartnerLoading,
+   },
+ ] = useLazyQuery<Query>(
+   user.role === Role.municipality
+     ? SkilavottordAllRecyclingPartnersByTypeQuery
+     : SkilavottordAllRecyclingPartnersQuery,
+   {
+     ssr: false,
+     variables:
+       user.role === Role.municipality
+         ? { isMunicipality: false, municipalityId: user?.partnerId }
+         : {},
+   },
+ )

226-228: Handle undefined municipalityId safely in labels

In constructing the label for recyclingPartners, the ternary check on partner.municipalityId should ensure that undefined or null values are handled properly to avoid displaying undefined - companyName.

Consider using a more robust nullish coalescing operator:

- label: partner.municipalityId
+ label: partner.municipalityId ?? ''

Or adjust the ternary condition:

- label: partner.municipalityId
+ label: partner.municipalityId
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 525e7f7 and d1108ea.

📒 Files selected for processing (9)
  • apps/skilavottord/web/auth/utils.ts (1 hunks)
  • apps/skilavottord/web/components/NavigationLinks/NavigationLinks.tsx (1 hunks)
  • apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (9 hunks)
  • apps/skilavottord/web/screens/AccessControlCompany/AccessControlCompany.tsx (2 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanies.tsx (3 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (5 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (8 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (5 hunks)
  • apps/skilavottord/ws/src/app/modules/accessControl/accessControl.service.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/skilavottord/web/auth/utils.ts
👮 Files not reviewed due to content moderation or server errors (2)
  • apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx
  • apps/skilavottord/web/screens/AccessControlCompany/AccessControlCompany.tsx
🧰 Additional context used
📓 Path-based instructions (8)
apps/skilavottord/web/components/NavigationLinks/NavigationLinks.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/accessControl/accessControl.service.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControlCompany/AccessControlCompany.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanies.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
📓 Learnings (1)
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)
Learnt from: birkirkristmunds
PR: island-is/island.is#17109
File: apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx:336-360
Timestamp: 2024-12-10T15:10:49.998Z
Learning: In the `RecyclingCompanyForm` component (`apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx`), the `isMunicipality` checkbox must remain in the DOM for all users since its value is stored in the database. However, only users with the developer role can manipulate it through the UI. This ensures that the checkbox value is maintained correctly while restricting interaction to authorized users.
🔇 Additional comments (12)
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (2)

Line range hint 169-205: Well-structured component rendering

The component rendering follows NextJS best practices with:

  • Proper loading state handling
  • Consistent layout structure
  • Clear component composition

112-114: Add null check for partnerId in refetchQueries

The partnerId could be undefined when passed to the refetch query, which might cause unexpected behavior.

Let's verify the handling of undefined partnerId in the codebase:

apps/skilavottord/web/components/NavigationLinks/NavigationLinks.tsx (1)

1-11: LGTM! Clean imports and well-typed props.

apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (1)

39-40: LGTM! Proper mutation field additions

The new fields isMunicipality and municipalityId are correctly added to the mutation response type.

apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanies.tsx (3)

33-49: LGTM! Well-structured GraphQL query

The new query properly handles type-specific filtering with correct variable types.


77-81: Add null check for municipality role handling

This addresses a previously identified issue with partner ID assignment.

-  if (hasMunicipalityRole(user?.role)) {
+  if (user?.role && hasMunicipalityRole(user.role)) {

104-126: 🛠️ Refactor suggestion

Refactor routing logic and investigate BASE-PATH issue

  1. The routing logic is duplicated between handleCreate and handleUpdate
  2. There's a comment about BASE-PATH duplication that needs investigation

Suggested refactor:

+  const getRoutePath = (type: 'create' | 'edit', id?: string) => {
+    const base = isMunicipality ? routes.municipalities : routes.recyclingCompanies;
+    const path = type === 'create' ? base.add : base.edit;
+    return id ? { pathname: path, query: { id } } : { pathname: path };
+  }

   const handleCreate = () => {
-    if (isMunicipality) {
-      router.push({
-        pathname: routes.municipalities.add,
-      })
-    } else {
-      router.push({
-        pathname: routes.recyclingCompanies.add,
-      })
-    }
+    router.push(getRoutePath('create'));
   }

   const handleUpdate = (id: string) => {
-    if (isMunicipality) {
-      router.push({
-        pathname: routes.municipalities.edit,
-        query: { id },
-      })
-    } else {
-      router.push({
-        pathname: routes.recyclingCompanies.edit,
-        query: { id },
-      })
-    }
+    router.push(getRoutePath('edit', id));
   }
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (3)

221-224: Ensure consistency of partners data structure

Merging data from recyclingPartnerData and recyclingPartnerByIdData into partners may lead to inconsistent data structures if the returned data differs. Verify that both data sources return data in the same format and handle any discrepancies to prevent runtime errors.


234-247: Simplify roles filtering logic for better readability

The current roles filtering logic involves multiple filters and conditions, which can be simplified to enhance readability and maintainability.

Consider refactoring:

const roles = Object.keys(AccessControlRole)
  .filter((role) => {
    if (!hasDeveloperRole(user?.role) && role === Role.developer) {
      return false
    }
    if (user.role === Role.municipality) {
      return [Role.recyclingCompany, Role.recyclingCompanyAdmin, Role.municipality].includes(role)
    }
    return true
  })
  .map((role) => ({
    label: getRoleTranslation(role as Role, activeLocale),
    value: role,
  }))

255-263: Ensure partners data is fetched before opening modal

When opening the create access control modal, ensure that the partners data is fetched before rendering the modal to prevent potential undefined data issues.

Consider adding a loading state or disabling the button until data is ready.

apps/skilavottord/ws/src/app/modules/accessControl/accessControl.service.ts (2)

68-69: Optimize database query for large partnerIds arrays

Using the IN operator with a potentially large partnerIds array can lead to performance issues. Consider implementing pagination, batching, or alternative querying strategies for handling large datasets.


37-66: ⚠️ Potential issue

Add safeguards to recursive getAllCompanyIds function

The recursive getAllCompanyIds function lacks protection against circular references and unchecked recursion depth, which could lead to stack overflows or performance issues.

Implement safeguards by tracking visited partnerIds and limiting recursion depth:

- const getAllCompanyIds = async (partnerId: string) => {
-   partnerIds.push(partnerId)
-   const subCompanies = await RecyclingPartnerModel.findAll({
-     where: { municipalityId: partnerId },
-   })
-   for (const subCompany of subCompanies) {
-     await getAllCompanyIds(subCompany.companyId)
-   }
- }
+ const getAllCompanyIds = async (
+   partnerId: string,
+   visited = new Set<string>(),
+   depth = 0,
+ ) => {
+   const MAX_DEPTH = 100
+   if (depth > MAX_DEPTH || visited.has(partnerId)) return
+   visited.add(partnerId)
+   partnerIds.push(partnerId)
+   const subCompanies = await RecyclingPartnerModel.findAll({
+     where: { municipalityId: partnerId },
+   })
+   for (const subCompany of subCompanies) {
+     await getAllCompanyIds(subCompany.companyId, visited, depth + 1)
+   }
+ }

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Outside diff range and nitpick comments (12)
apps/skilavottord/ws/src/app/modules/accessControl/accessControl.model.ts (1)

Line range hint 66-73: LGTM! The new partnerId field is well-structured.

The implementation follows TypeScript, GraphQL, and Sequelize best practices with proper decorators and type safety.

Consider adding a JSDoc comment to document the purpose of this field and its relationship with RecyclingPartnerModel:

+ /**
+  * ID of the associated recycling partner. Used to establish relationship
+  * between access control entries and recycling partners for municipality management.
+  */
  @Field({ nullable: true })
  @ForeignKey(() => RecyclingPartnerModel)
  @Column({
    type: DataType.STRING,
    field: 'partner_id',
    allowNull: true,
  })
  partnerId?: string
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (2)

112-116: Add TypeScript types for query variables

Consider adding explicit TypeScript types for the query variables to improve type safety and maintainability.

+ interface RecyclingPartnersQueryVars {
+   isMunicipalityPage: boolean
+   municipalityId: string | null
+ }

  refetchQueries: [
    {
      query: SkilavottordRecyclingPartnerQuery,
      variables: { input: { companyId: id } },
    },
    {
      query: SkilavottordRecyclingPartnersQuery,
-     variables: {
-       isMunicipalityPage: isMunicipalityPage,
-       municipalityId: partnerId,
-     },
+     variables: {
+       isMunicipalityPage,
+       municipalityId: partnerId,
+     } as RecyclingPartnersQueryVars,
    },
  ],

128-130: Add cleanup function to useEffect

Consider adding a cleanup function to handle component unmounting, following React best practices.

  React.useEffect(() => {
    setValue('isMunicipality', isMunicipalityPage)
+   return () => {
+     // Reset the form value on unmount if needed
+     setValue('isMunicipality', false)
+   }
  }, [isMunicipalityPage, setValue])
apps/skilavottord/web/screens/DeregisterVehicle/Overview/Overview.tsx (1)

Line range hint 52-195: Excellent implementation following NextJS and TypeScript best practices.

The component demonstrates:

  • Proper error handling and loading states
  • Type-safe implementation
  • Efficient data fetching with pagination
  • Clean and maintainable structure

Consider implementing React Query or SWR for better cache management and automatic revalidation of data in future iterations.

apps/skilavottord/web/i18n/locales/translation.d.ts (1)

478-493: Consider enhancing type safety for municipality interfaces.

The new Municipalities and Municipality interfaces reuse existing patterns, which is good. However, consider adding more specific types for municipality-specific fields that might have unique validation requirements.

Example enhancement:

 export interface Municipality {
   view: View
   add: Add
-  form: RecyclingCompanyForm
+  form: {
+    inputs: MunicipalityFormInputs
+    buttons: FormButtons
+  }
 }

+export interface MunicipalityFormInputs extends FormInputs {
+  // Add municipality-specific fields with appropriate validation rules
+  region?: {
+    label: string
+    placeholder: string
+    rules: {
+      required: string
+    }
+  }
+}
apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx (2)

68-71: Initialize component states in useEffect

The useEffect hook initializes the visibility of company and municipality selection inputs. Confirm that this aligns with the intended initial state when the modal is opened.

Consider whether the useEffect is necessary here, as the initial state values are already set in the useState declarations.


73-91: Simplify handleRoleOnChange logic

The handleRoleOnChange function has nested conditions that could be refactored for clarity and maintainability. Consider simplifying the logic to reduce complexity.

Here's a possible refactor:

 const handleRoleOnChange = (e: Option) => {
-  if (hasMunicipalityRole(user?.role)) {
-    if (e && e.value === Role.municipality) {
-      setShowCompaniesSelection(false)
-    } else {
-      setShowCompaniesSelection(true)
-    }
-    setShowMunicipalitiesSelection(false)
-  } else if (hasRecyclingFundRole(user?.role)) {
-    if (e && e.value === Role.municipality) {
-      setShowCompaniesSelection(false)
-      setShowMunicipalitiesSelection(true)
-    } else {
-      setShowMunicipalitiesSelection(false)
-      setShowCompaniesSelection(true)
-    }
-  }
+  const isMunicipalityRoleSelected = e && e.value === Role.municipality
+  if (hasMunicipalityRole(user?.role)) {
+    setShowCompaniesSelection(!isMunicipalityRoleSelected)
+    setShowMunicipalitiesSelection(false)
+  } else if (hasRecyclingFundRole(user?.role)) {
+    setShowCompaniesSelection(!isMunicipalityRoleSelected)
+    setShowMunicipalitiesSelection(isMunicipalityRoleSelected)
+  }
 }
apps/skilavottord/web/screens/AccessControl/components/AccessControlUpdate/AccessControlUpdate.tsx (2)

75-78: Consider extracting role-based logic

The inline role check creates tight coupling. Consider extracting this logic to a utility function for better maintainability.

- partnerId:
-   role.value === Role.municipality
-     ? municipalityId?.value
-     : partnerId?.value || null,
+ partnerId: getPartnerId(role.value, municipalityId?.value, partnerId?.value),

94-97: Simplify partner ID requirement check

The current check could be simplified using array inclusion.

- partnerIdRequired={
-   watch('role')?.value === Role.recyclingCompanyAdmin ||
-   watch('role')?.value === Role.recyclingCompany
- }
+ partnerIdRequired={[Role.recyclingCompanyAdmin, Role.recyclingCompany].includes(watch('role')?.value)}
apps/skilavottord/web/screens/CompanyInfo/CompanyInfo.tsx (1)

28-28: Consider prop type validation

The PageHeader component is used without TypeScript prop validation. Ensure proper type checking.

Add prop types validation:

interface PageHeaderProps {
  title: string;
  info?: string;
}

Also applies to: 105-105

apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)

278-311: Consider enhancing error handling for municipality selection.

While the implementation is clean, consider adding more specific error messages for municipality selection failures.

 <Select
   name={name}
   label={t.recyclingCompany.form.inputs.municipality.label}
   placeholder={t.recyclingCompany.form.inputs.municipality.placeholder}
   size="md"
   value={municipalities?.find((option) => option.value === value)}
   hasError={!!errors?.municipality?.message}
-  errorMessage={errors?.municipality?.message}
+  errorMessage={errors?.municipality?.message || t.recyclingCompany.form.inputs.municipality.error}
   backgroundColor="blue"
   options={municipalities}
   onChange={onChange}
   isCreatable
 />
apps/skilavottord/ws/src/app/modules/recyclingRequest/recyclingRequest.service.ts (1)

46-48: Consider enhancing error handling for disposalStationId retrieval.

While the addition of disposalStationId retrieval is good, consider adding specific error handling for cases where the ID cannot be retrieved.

 const disposalStationId =
-  await this.recyclingPartnerService.getGetPayingPartnerId(disposalStation)
+  await this.recyclingPartnerService.getGetPayingPartnerId(disposalStation)
+    .catch((error) => {
+      this.logger.error('Failed to retrieve disposal station ID', { error, disposalStation })
+      throw new Error(`Invalid disposal station: ${disposalStation}`)
+    })
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d1108ea and a2ce8ec.

📒 Files selected for processing (21)
  • apps/skilavottord/web/auth/utils.ts (1 hunks)
  • apps/skilavottord/web/i18n/locales/en.json (5 hunks)
  • apps/skilavottord/web/i18n/locales/is.json (6 hunks)
  • apps/skilavottord/web/i18n/locales/translation.d.ts (7 hunks)
  • apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (12 hunks)
  • apps/skilavottord/web/screens/AccessControl/components/AccessControlCreate/AccessControlCreate.tsx (5 hunks)
  • apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx (4 hunks)
  • apps/skilavottord/web/screens/AccessControl/components/AccessControlUpdate/AccessControlUpdate.tsx (6 hunks)
  • apps/skilavottord/web/screens/AccessControlCompany/AccessControlCompany.tsx (3 hunks)
  • apps/skilavottord/web/screens/CompanyInfo/CompanyInfo.tsx (2 hunks)
  • apps/skilavottord/web/screens/DeregisterVehicle/Overview/Overview.tsx (2 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanies.tsx (3 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (5 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (7 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (5 hunks)
  • apps/skilavottord/web/screens/RecyclingFund/Overview/Overview.tsx (4 hunks)
  • apps/skilavottord/ws/src/app/modules/accessControl/accessControl.model.ts (1 hunks)
  • apps/skilavottord/ws/src/app/modules/accessControl/accessControl.service.ts (2 hunks)
  • apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts (4 hunks)
  • apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts (3 hunks)
  • apps/skilavottord/ws/src/app/modules/recyclingRequest/recyclingRequest.service.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/skilavottord/ws/src/app/modules/accessControl/accessControl.service.ts
  • apps/skilavottord/web/screens/AccessControlCompany/AccessControlCompany.tsx
🧰 Additional context used
📓 Path-based instructions (19)
apps/skilavottord/ws/src/app/modules/accessControl/accessControl.model.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/CompanyInfo/CompanyInfo.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/DeregisterVehicle/Overview/Overview.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingFund/Overview/Overview.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/recyclingRequest/recyclingRequest.service.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanies.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControl/components/AccessControlCreate/AccessControlCreate.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControl/components/AccessControlUpdate/AccessControlUpdate.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/i18n/locales/is.json (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/i18n/locales/en.json (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/auth/utils.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/i18n/locales/translation.d.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
📓 Learnings (1)
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)
Learnt from: birkirkristmunds
PR: island-is/island.is#17109
File: apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx:336-360
Timestamp: 2024-12-10T15:10:49.998Z
Learning: In the `RecyclingCompanyForm` component (`apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx`), the `isMunicipality` checkbox must remain in the DOM for all users since its value is stored in the database. However, only users with the developer role can manipulate it through the UI. This ensures that the checkbox value is maintained correctly while restricting interaction to authorized users.
🔇 Additional comments (52)
apps/skilavottord/ws/src/app/modules/accessControl/accessControl.model.ts (1)

Line range hint 66-77: Verify database migration for the new partnerId field.

The model changes look correct, but we should ensure there's a corresponding database migration for this new field.

apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (1)

43-43: Add municipalityId to the mutation response

The municipalityId field is included in the query response but missing in the mutation response. This inconsistency could lead to stale data after updates.

Also applies to: 47-63

apps/skilavottord/web/screens/DeregisterVehicle/Overview/Overview.tsx (2)

3-4: LGTM! Well-organized imports following NextJS best practices.

The imports are logically grouped by source/type, enhancing code readability and maintainability.

Also applies to: 13-14, 21-21, 23-23, 27-27, 29-29, 32-32


171-171: Good refactoring to use the shared PageHeader component.

The change improves component reusability and standardizes header presentation across the application.

Let's verify the PageHeader component implementation:

✅ Verification successful

Let me gather more information about the PageHeader component implementation.


PageHeader component is well-implemented and consistently used

The PageHeader component is properly implemented using Island UI components and is consistently used across multiple screens in the application. It:

  • Accepts required title and info props
  • Uses appropriate layout components (Box, GridRow, GridColumn)
  • Implements consistent styling with Text variant="h1" and Tooltip
  • Shows consistent usage pattern across 7 different screens
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify PageHeader component implementation and usage

# Check PageHeader component implementation
ast-grep --pattern 'export const PageHeader = ({ title, info }: Props) => {
  $$$
}'

# Check for consistent usage across the application
rg -A 2 '<PageHeader.*title=.*info=.*>'

Length of output: 2545


Script:

#!/bin/bash
# Search for PageHeader component definition
fd PageHeader.tsx --exec cat {}

Length of output: 974

apps/skilavottord/web/i18n/locales/translation.d.ts (5)

33-33: LGTM: Translation interface updated correctly.

The addition of the municipalities property to the Translation interface is consistent with the existing pattern and properly typed.


75-75: LGTM: ModalInputs interface updated correctly.

The addition of the municipality property to the ModalInputs interface follows the existing pattern by reusing the Name type.


469-469: LGTM: RecyclingCompaniesButtons interface updated correctly.

The addition of the addMunicipality property to the RecyclingCompaniesButtons interface maintains consistency with existing button properties.


561-561: LGTM: RecyclingFundSidenav interface updated correctly.

The addition of municipalityTitle and municipalities properties to the RecyclingFundSidenav interface follows the existing naming pattern.

Also applies to: 565-565


578-578: Verify the route configuration.

The addition of the municipalities property to the Routes interface using RecyclingCompaniesClass type is consistent. However, verify that the route structure matches the actual routing implementation.

✅ Verification successful

Route configuration is correctly implemented and matches the type definition

The route configuration for municipalities is properly implemented and used consistently throughout the codebase:

  • The type definition in translation.d.ts correctly uses RecyclingCompaniesClass type for the municipalities route
  • The route is actively used in components:
    • RecyclingCompanies.tsx uses routes.municipalities.baseRoute, routes.municipalities.add, and routes.municipalities.edit
    • NavigationLinks.tsx implements the navigation using routes.municipalities.baseRoute
    • Route checks are properly implemented in components like RecyclingCompanyUpdate and RecyclingCompanyCreate
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify route configuration matches implementation
# Test: Search for municipality route definitions in the codebase
rg -t typescript -t javascript "municipalities.*route" ./apps/skilavottord/web

Length of output: 115


Script:

#!/bin/bash
# Search for route configurations and usages of municipalities
rg -g '*.{ts,tsx,js,jsx}' 'municipalities' ./apps/skilavottord/web

Length of output: 5320


Script:

#!/bin/bash
# Look for route definitions in common routing files
fd -e ts -e tsx -e js -e jsx "routes|router" ./apps/skilavottord/web --exec cat {}

Length of output: 1152


Script:

#!/bin/bash
# Check the type definition and its usage
ast-grep --pattern 'interface $_ {
  $$$
  municipalities: $_
  $$$
}'

Length of output: 3776

apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts (2)

9-9: LGTM!

The Op import from sequelize is correctly added and is necessary for the query conditions.


28-52: 🛠️ Refactor suggestion

Improve method implementation and add error handling

  1. The comment on line 32 is misleading as it doesn't match the actual logic
  2. The method could be simplified to use a single query with dynamic conditions
  3. Error handling should be added

Apply this diff to improve the implementation:

 async findRecyclingPartners(
   isMunicipalityPage: boolean,
   municipalityId: string | null,
 ): Promise<RecyclingPartnerModel[]> {
-  // If Role.municipality, return all recycling partners that are not municipalities
-  if (municipalityId) {
-    return await this.recyclingPartnerModel.findAll({
-      where: {
-        isMunicipality: false,
-        municipalityId: municipalityId,
-      },
-    })
-  }
-
-  if (isMunicipalityPage) {
-    return await this.recyclingPartnerModel.findAll({
-      where: { isMunicipality: true },
-    })
-  }
-  return await this.recyclingPartnerModel.findAll({
-    where: {
-      [Op.or]: [{ isMunicipality: false }, { isMunicipality: null }],
-    },
-  })
+  try {
+    const whereCondition = municipalityId
+      ? { isMunicipality: false, municipalityId }
+      : isMunicipalityPage
+      ? { isMunicipality: true }
+      : {
+          [Op.or]: [{ isMunicipality: false }, { isMunicipality: null }],
+        };
+
+    return await this.recyclingPartnerModel.findAll({
+      where: whereCondition,
+    });
+  } catch (error) {
+    throw new Error(`Failed to fetch recycling partners: ${error.message}`);
+  }
 }
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts (2)

20-20: LGTM!

The addition of Role.municipality to the authorization roles is consistent across all methods and aligns with the PR objectives.

Also applies to: 30-30, 55-55, 66-66, 87-87


22-27: 🛠️ Refactor suggestion

Align method name with GraphQL query name

The method name should match the GraphQL query name for consistency and clarity.

Apply this diff to fix the naming:

 @Query(() => [RecyclingPartnerModel], {
   name: 'skilavottordAllRecyclingPartners',
 })
-async getAllRecyclingPartners(): Promise<RecyclingPartnerModel[]> {
+async skilavottordAllRecyclingPartners(): Promise<RecyclingPartnerModel[]> {
   return this.recyclingPartnerService.findAll()
 }
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (2)

123-131: Simplify success handling logic

The success handling code is duplicated and can be simplified.

Apply this diff to simplify the code:

-      if (isMunicipalityPage) {
-        router.push(routes.municipalities.baseRoute).then(() => {
-          toast.success(t.recyclingCompany.add.added)
-        })
-      } else {
-        router.push(routes.recyclingCompanies.baseRoute).then(() => {
-          toast.success(t.recyclingCompany.add.added)
-        })
-      }
+      const route = isMunicipalityPage
+        ? routes.municipalities.baseRoute
+        : routes.recyclingCompanies.baseRoute
+      router.push(route).then(() => {
+        toast.success(t.recyclingCompany.add.added)
+      })

75-85: 🛠️ Refactor suggestion

Improve form initialization and validation

The form initialization could be improved to handle null values and add validation.

Apply this diff to improve the form handling:

 const {
   control,
   handleSubmit,
   formState: { errors },
 } = useForm({
   mode: 'onChange',
-  defaultValues: {
-    isMunicipality: isMunicipalityPage,
-    municipalityId: partnerId,
-  },
+  defaultValues: isMunicipalityPage
+    ? { isMunicipality: true }
+    : { isMunicipality: false, municipalityId: partnerId || '' },
 })
apps/skilavottord/web/screens/AccessControl/components/AccessControlCreate/AccessControlCreate.tsx (6)

1-1: Imports are correctly added

The addition of useContext, useEffect, UserContext, and hasMunicipalityRole imports is appropriate for the new functionality related to municipalities and user roles.

Also applies to: 12-13


23-23: Include municipalities in props interface

Adding municipalities to the AccessControlCreateProps interface ensures that the component can receive and utilize the list of municipalities.


38-38: Retrieve user data using useContext

Using const { user } = useContext(UserContext) correctly accesses the user information from the context for role-based logic within the component.


65-73: Ensure all required fields are submitted

In the handleOnSubmit function, verify that all required fields, especially the newly added municipalityId, are correctly included in the submission data and validated.


77-80: Reset form state when modal visibility changes

The useEffect hook resets the form whenever the show prop changes, ensuring that the form is cleared when the modal is reopened. This enhances the user experience by preventing residual data from previous entries.


90-90: Pass municipalities prop to AccessControlModal

Providing the municipalities prop to AccessControlModal allows the modal to display municipality options, aligning with the new feature requirements.

apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx (6)

1-8: Imports are correctly updated

The inclusion of useContext, useEffect, useState, and kennitala imports supports the added functionality for role handling and national ID validation.


13-21: Update interface to include new props

Adding municipalities and currentPartner to AccessControlModalProps enables the component to handle municipalities and existing partner data effectively.


64-67: Retrieve user context and initialize state

Using useContext(UserContext) to access user, and initializing showCompanies and showMunicipalities states, sets up the component for dynamic rendering based on user roles.


208-211: Ensure handleRoleOnChange is called correctly

In the Select component for role, the onChange handler correctly updates the form value and triggers handleRoleOnChange to adjust the form based on the selected role.


216-249: Conditional rendering of partnerId selection

The partnerId selection is conditionally rendered based on showCompanies. Ensure that this logic accurately reflects when a user should select a recycling partner.


250-279: Add municipalityId selection for relevant roles

Introducing the municipalityId selection when showMunicipalities is true allows users with certain roles to select a municipality. Ensure that the validation rules and error handling for this field are correctly implemented.

apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (6)

127-153: Optimize data fetching with useLazyQuery hooks

Replacing useQuery with useLazyQuery for fetching recycling partner data allows more controlled and efficient data retrieval based on user interactions and roles.


224-227: Ensure correct retrieval of accessControls data

The accessControls variable consolidates data from different queries. Verify that it correctly handles data from all potential sources to prevent missing or inconsistent access control entries.


255-267: Simplify roles filtering logic

The roles filtering logic can be simplified and made more readable.

Apply this diff to improve the filtering logic:

 const roles = Object.keys(AccessControlRole)
-  .filter((role) =>
-    !hasDeveloperRole(user?.role) ? role !== Role.developer : role,
-  )
-  .filter((role) => {
-    if (hasMunicipalityRole(Role.municipality)) {
-      return (
-        role === Role.recyclingCompany ||
-        role === Role.recyclingCompanyAdmin ||
-        role === Role.municipality
-      )
-    }
-    return role
-  })
+  .filter((role) => {
+    if (!hasDeveloperRole(user?.role) && role === Role.developer) {
+      return false
+    }
+    if (hasMunicipalityRole(user?.role)) {
+      return [
+        Role.recyclingCompany,
+        Role.recyclingCompanyAdmin,
+        Role.municipality,
+      ].includes(role as Role)
+    }
+    return true
+  })
   .map((role) => ({
     label: getRoleTranslation(role as Role, activeLocale),
     value: role,
   }))

This suggestion aligns with a previous review comment.


276-284: Ensure partners data is fetched before rendering modal

When opening the create access control modal, ensure that the partners data is fetched based on the user's role to prevent any potential data issues.


339-347: Update layout components and pass new props

Replacing Sidenav with NavigationLinks and updating the PageHeader enhances the UI. Passing municipalities to AccessControlCreate aligns with the new feature implementation.


205-211: ⚠️ Potential issue

Include all data sources in error and loading states

Ensure that the error, loading, and isData variables include all relevant data sources (recyclingPartnerData, recyclingPartnerByIdData, and accessControlsData) to accurately reflect the component's state.

Apply this diff to include all data sources:

 const error =
-  recyclingPartnerError || accessControlsError || recyclingPartnerByIdError
 const loading =
-  recyclingPartnerLoading || accessControlsLoading || recyclingPartnerByIdLoading
 const isData = 
-  !!recyclingPartnerData || !!accessControlsData
+  recyclingPartnerError || accessControlsError || recyclingPartnerByIdError
+  recyclingPartnerLoading || accessControlsLoading || recyclingPartnerByIdLoading
+  !!recyclingPartnerData || !!recyclingPartnerByIdData || !!accessControlsData

This comment addresses a similar concern mentioned in previous reviews.

apps/skilavottord/web/auth/utils.ts (3)

13-19: Introduce role-checking utility functions

Adding hasDeveloperRole, hasMunicipalityRole, and hasRecyclingFundRole functions improves code readability and reusability when checking user roles throughout the application.


27-40: Update hasPermission function with new roles and pages

Modifying the permittedRoutes object to include the municipality role and updating permitted pages for existing roles ensures that access control aligns with the application's updated role definitions.


13-16: Potential impact of removing 'deregisterVehicleKM'

Removing 'deregisterVehicleKM' from the Page type might affect parts of the application that rely on this page. Ensure that this page is deprecated and no longer in use.

Run the following script to check for any remaining references to 'deregisterVehicleKM':

✅ Verification successful

No references to deregisterVehicleKM found in the codebase

Since no references to deregisterVehicleKM were found in any form (camelCase, kebab-case, or case-insensitive variations) across the entire codebase, it appears that this page has been completely removed and is no longer in use. The removal of this value from the Page type is safe.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for any usages of 'deregisterVehicleKM' in the codebase.

# Test: Find all occurrences of 'deregisterVehicleKM'
rg 'deregisterVehicleKM'

Length of output: 24


Script:

#!/bin/bash
# Let's try a case-insensitive search and also look for kebab-case variations
rg -i "deregister.*vehicle.*km|deregister-vehicle-km"

# Also search for any files with similar naming patterns
fd -i "deregister.*vehicle.*km"

Length of output: 89

apps/skilavottord/web/screens/AccessControl/components/AccessControlUpdate/AccessControlUpdate.tsx (1)

60-63: Verify municipality ID mapping logic

The code assumes that municipality's companyId matches the recyclingPartner's companyId. This assumption might lead to incorrect mappings.

✅ Verification successful

Based on the codebase analysis, I can now provide a final response regarding the municipality ID mapping concern:

The municipality ID mapping is correctly implemented

The code is working as intended because:

  1. The municipalities array is populated from recycling partners that have isMunicipality flag set to true
  2. The companyId is used consistently as the value field for both municipalities and recycling partners
  3. The mapping between municipality and recycling partner is done through the companyId field, which serves as a common identifier
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if municipality IDs match company IDs in the codebase
rg -A 5 "companyId.*municipality" 

Length of output: 35


Script:

#!/bin/bash
# Let's check the schema/types and usages to understand the relationship
# First, let's find type definitions related to municipalities and recycling partners
ast-grep --pattern 'interface $_Municipality {
  $$$
}'

# Also check for any type with companyId
ast-grep --pattern 'interface $_ {
  companyId: $_
  $$$
}'

# And check how municipalities are used with recycling partners
rg -B 3 -A 3 "municipalities.*recyclingPartner" 

Length of output: 2088


Script:

#!/bin/bash
# Let's check the component's props and the municipalities type
ast-grep --pattern 'type $_Props = {
  $$$
  municipalities: $_
  $$$
}'

# Check how municipalities are structured
rg -B 2 -A 2 "municipalities.*value.*label"

# Look for recyclingPartner type definition
ast-grep --pattern 'type $_RecyclingPartner = {
  $$$
}'

Length of output: 179


Script:

#!/bin/bash
# Let's check the interface definitions and type declarations
ast-grep --pattern 'interface $_ {
  municipalities: $_
  $$$
}'

# Look for municipality option type definitions
rg -B 3 -A 3 "type.*Municipality"

# Check how the municipalities array is populated
rg -B 3 -A 3 "municipalities.*=" 

Length of output: 34477

apps/skilavottord/web/screens/RecyclingFund/Overview/Overview.tsx (1)

119-119: Verify component integration

The replacement of Sidenav with NavigationLinks and addition of PageHeader needs verification for proper role-based access.

Also applies to: 139-139

✅ Verification successful

Let me check the NavigationLinks component implementation and its role-based access control to complete the verification.


Let me check the implementation of the role-based utility function and the user context to complete the verification.


NavigationLinks component properly handles role-based access

The NavigationLinks component correctly implements role-based access control:

  • It uses UserContext to access the user's role
  • Implements proper role checks using hasMunicipalityRole utility
  • Conditionally renders navigation items based on user roles
  • Maintains the same role-based access control as the previous Sidenav implementation
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check NavigationLinks usage across the codebase
rg -A 5 "NavigationLinks.*activeSection"

Length of output: 3591


Script:

#!/bin/bash
# Check NavigationLinks implementation
ast-grep --pattern 'const NavigationLinks = $_'

# Check for any auth/role checks in the component
rg -A 5 "auth|role|permission" apps/skilavottord/web/components/NavigationLinks

Length of output: 6366


Script:

#!/bin/bash
# Check role utility implementation
ast-grep --pattern 'export const hasMunicipalityRole = $_'

# Check UserContext implementation
ast-grep --pattern 'export const UserContext = $_'

# Check if there are any other role-based checks
rg "user?.role" apps/skilavottord/web

Length of output: 639

apps/skilavottord/web/screens/CompanyInfo/CompanyInfo.tsx (1)

105-105: Verify PageHeader accessibility

The PageHeader component replaces direct Text components. Ensure it maintains proper heading hierarchy and accessibility.

✅ Verification successful

PageHeader component maintains proper heading hierarchy and accessibility

The PageHeader component in apps/skilavottord/web/components/PageHeader/PageHeader.tsx correctly implements heading hierarchy by using:

  • Text component with variant="h1" and as="h1" props
  • Proper semantic structure with GridRow/GridColumn for layout
  • Tooltip for additional information accessibility
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check PageHeader implementation for accessibility attributes
ast-grep --pattern 'export const PageHeader = $_ => {
  $$$
  return (
    $$$
    <h1 $_>$$$</h1>
    $$$
  )
}'

Length of output: 115


Script:

#!/bin/bash
# Let's try a broader search for PageHeader component
fd PageHeader --type f --exec cat {}

# Also search for any h1 tags in the codebase to understand heading hierarchy
ast-grep --pattern '<h1 $_>$$$</h1>'

# Search for PageHeader usage patterns
rg "PageHeader" -A 2

Length of output: 57260

apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanies.tsx (3)

4-31: LGTM! Clean import organization.

The new imports for municipality support and UI components are well-structured and properly organized.


Line range hint 133-152: LGTM! Clean UI component integration.

The NavigationLinks and PageHeader components are well-integrated and improve the overall UI consistency.


80-84: Verify partnerId assignment for municipality users.

The partnerId assignment logic for municipality users should be verified to ensure it correctly handles all edge cases.

✅ Verification successful

Let me check the implementation of hasMunicipalityRole and related role checks to ensure the partnerId assignment is consistent.


Let me check for the implementation of hasMunicipalityRole and the Role enum specifically for the skilavottord application.


Let me check the complete Role enum definition and the usage of municipality role in the codebase.


The partnerId assignment for municipality users is correctly implemented.

The code is consistent with the rest of the codebase. The implementation shows:

  1. hasMunicipalityRole is properly defined in auth/utils.ts and checks for Role.municipality
  2. The Role enum in user.model.ts includes the municipality role
  3. The partnerId assignment pattern is used consistently across the codebase:
    • In vehicle resolver: partnerId: user.role === Role.municipality ? user.partnerId : null
    • In recycling company screens: if (hasMunicipalityRole(user?.role)) { partnerId = user?.partnerId }
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for other instances of partnerId assignment for municipalities
rg "partnerId.*municipality" -A 3

Length of output: 1966


Script:

#!/bin/bash
# Check implementation of hasMunicipalityRole and related role checks
ast-grep --pattern 'function hasMunicipalityRole($_) { $$$ }'

# Check Role enum definition
rg "enum.*Role" -A 10

# Check other usages of user?.role with municipality
rg "user\?\.role.*municipality" -A 2

Length of output: 66127


Script:

#!/bin/bash
# Search for Role enum in skilavottord
rg "enum.*Role" -A 5 apps/skilavottord/

# Search for hasMunicipalityRole implementation
ast-grep --pattern 'const hasMunicipalityRole = $_' apps/skilavottord/web/

# Check other role-related functions in the same context
rg "Role\." -A 2 apps/skilavottord/web/screens/RecyclingCompanies/

Length of output: 889


Script:

#!/bin/bash
# Get complete Role enum definition
rg -A 10 "export enum Role" apps/skilavottord/

# Check all usages of municipality role
rg "Role\.municipality" apps/skilavottord/

# Check implementation of hasMunicipalityRole and its imports
rg -A 3 "hasMunicipalityRole" apps/skilavottord/

Length of output: 12227

apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (2)

Line range hint 25-45: LGTM! Well-typed interface changes.

The interface updates properly accommodate the new municipality functionality with appropriate typing.


336-361: LGTM! Proper implementation of developer-only UI control.

The implementation correctly maintains the checkbox in the DOM while restricting UI manipulation to developers, as per the established pattern.

apps/skilavottord/ws/src/app/modules/recyclingRequest/recyclingRequest.service.ts (1)

Line range hint 257-267: LGTM! Proper partner validation implementation.

The partner validation logic is well-implemented with clear error messages and proper logging.

apps/skilavottord/web/i18n/locales/en.json (4)

368-372: LGTM: Navigation and titles are properly translated.

The translations for municipality-related navigation items and titles are correctly implemented in English.


Line range hint 376-396: LGTM: Recycling companies section translations are accurate.

The translations for recycling companies section, including the new municipality-related buttons and status indicators, are properly implemented in English.


Line range hint 647-667: Add missing translations in municipality section.

The municipality section is missing essential translations such as table headers, status indicators, and action buttons.

Add the following translations:

  "municipalities": {
    "title": "Municipalities",
+   "info": "Information about registered municipalities.",
+   "tableHeaders": {
+     "name": "Name",
+     "address": "Address",
+     "postnumber": "Postal Code",
+     "email": "Email",
+     "status": "Status"
+   },
+   "status": {
+     "active": "Active",
+     "inactive": "Inactive"
+   },
+   "buttons": {
+     "add": "Add Municipality",
+     "edit": "Edit",
+     "delete": "Delete"
+   },
    "municipality": {
      "view": {
        "title": "Municipality",
        "breadcrumb": "View",
        "updated": "Updated",
        "deleted": "Deleted"
      },
      "add": {
        "title": "Add Municipality",
        "breadcrumb": "Add",
        "added": "Added"
      }
    }
  }

653-653: ⚠️ Potential issue

Fix non-English content in English locale file.

These strings are in Icelandic instead of English:

  • Line 653: "Þú getur annaðhvort uppfært eða eytt móttökuaðila..."
  • Line 657-660: "Þegar nýju sveitarfélagi er bætt við..."

Apply this diff to fix the translations:

-        "info": "Þú getur annaðhvort uppfært eða eytt móttökuaðila. Vinsamlegast staðfestið að upplýsingar fyrirtækis séu rétt slegnar inn.",
+        "info": "You can either update or delete a municipality. Please verify that the municipality information is correct.",
-        "info": "Þegar nýju sveitarfélagi er bætt við, verður hann aðgengilegur í aðgangsstýringu. Vinsamlegast staðfestið að upplýsingar fyrirtækis séu rétt slegnar inn.",
+        "info": "When a new municipality is added, it will be available in access control. Please verify that the municipality information is correct.",

Also applies to: 657-660

apps/skilavottord/web/i18n/locales/is.json (3)

368-372: LGTM: Navigation and titles are properly translated.

The translations for municipality-related navigation items and titles are correctly implemented in Icelandic.


486-489: ⚠️ Potential issue

Add validation rules for municipality field.

The municipality field in the recycling company form lacks validation rules, unlike other required fields.

Apply this diff to add validation rules:

  "municipality": {
    "label": "Sveitarfélag",
-   "placeholder": "Sveitarfélag"
+   "placeholder": "Sveitarfélag",
+   "rules": {
+     "required": "Skylda er að fylla út sveitarfélag"
+   }
  }

651-667: ⚠️ Potential issue

Complete the municipality management section.

The municipality section is missing several essential elements:

  1. Table headers for the municipality list view
  2. Status indicators
  3. Action button translations
  4. Form input definitions

Add the missing translations:

  "municipalities": {
    "title": "Sveitarfélög",
+   "info": "Upplýsingar um skráð sveitarfélög.",
    "empty": "Ekkert sveitarfélag fannst",
+   "tableHeaders": {
+     "name": "Nafn",
+     "address": "Heimilisfang",
+     "postnumber": "Póstnúmer",
+     "email": "Netfang",
+     "status": "Staða"
+   },
+   "status": {
+     "active": "Virkt",
+     "inactive": "Óvirkt"
+   },
+   "buttons": {
+     "add": "Bæta við sveitarfélagi",
+     "edit": "Breyta",
+     "delete": "Eyða"
+   },
    "municipality": {
      "view": {
        "title": "Sveitarfélag",
        "breadcrumb": "Skoða",
-       "info": "Þú getur annaðhvort uppfært eða eytt móttökuaðila. Vinsamlegast staðfestið að upplýsingar fyrirtækis séu rétt slegnar inn.",
+       "info": "Þú getur annaðhvort uppfært eða eytt sveitarfélagi. Vinsamlegast staðfestið að upplýsingar sveitarfélags séu rétt slegnar inn.",
        "updated": "Uppfært",
        "deleted": "Eytt"
      },
      "add": {
        "title": "Bæta við sveitarfélagi",
        "breadcrumb": "Bæta við",
        "info": "Þegar nýju sveitarfélagi er bætt við, verður það aðgengilegt í aðgangsstýringu. Vinsamlegast staðfestið að upplýsingar sveitarfélags séu rétt slegnar inn.",
        "added": "Bætt við"
-     }
+     },
+     "form": {
+       "inputs": {
+         "name": {
+           "label": "Nafn",
+           "placeholder": "Nafn sveitarfélags",
+           "rules": {
+             "required": "Skylda er að fylla út nafn"
+           }
+         },
+         "email": {
+           "label": "Netfang",
+           "placeholder": "Netfang",
+           "rules": {
+             "required": "Skylda er að fylla út netfang",
+             "validate": "Netfang er ekki á réttu formi"
+           }
+         }
+       }
+     }
    }
  }

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (3)

55-66: Add error handling for the data transformation

The municipality data transformation could be more robust by handling potential undefined values and empty arrays.

Consider updating the transformation:

- const municipalities = data?.skilavottordRecyclingPartners.map(
+ const municipalities = data?.skilavottordRecyclingPartners?.map(
    (municipality) => ({
      label: municipality.companyName,
      value: municipality.companyId,
    }),
-  )
+  ) ?? []

281-315: Enhance accessibility for the municipality select component

While the implementation is functionally correct, consider adding ARIA attributes for better accessibility.

Add these attributes to the Select component:

 <Select
   name={name}
   label={t.recyclingCompany.form.inputs.municipality.label}
   placeholder={t.recyclingCompany.form.inputs.municipality.placeholder}
+  aria-label={t.recyclingCompany.form.inputs.municipality.label}
+  aria-required="true"
   size="md"
   value={municipalities?.find((option) => option.value === value)}
   hasError={!!errors?.municipality?.message}
   errorMessage={errors?.municipality?.message}
   backgroundColor="blue"
   options={municipalities}
   onChange={onChange}
   isCreatable
   isDisabled={hasMunicipalityRole(user?.role)}
 />

340-365: Consider using styled components instead of inline styles

While the implementation correctly maintains the checkbox in the DOM as required, the visibility control could be improved.

Consider using styled components or CSS classes:

- <div
-   style={{
-     display: user?.role && hasDeveloperRole(user.role) ? 'block' : 'none',
-   }}
- >
+ <Box
+   display={user?.role && hasDeveloperRole(user.role) ? 'block' : 'none'}
+ >
apps/skilavottord/web/screens/AccessControl/components/AccessControlCreate/AccessControlCreate.tsx (1)

81-84: Consider preserving form state on modal close

The current implementation clears the form whenever the modal is reopened. Consider if this is the desired behavior or if form state should be preserved in certain scenarios.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2ce8ec and 7e4ddbb.

📒 Files selected for processing (4)
  • apps/skilavottord/web/screens/AccessControl/components/AccessControlCreate/AccessControlCreate.tsx (5 hunks)
  • apps/skilavottord/web/screens/AccessControl/components/AccessControlUpdate/AccessControlUpdate.tsx (5 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (5 hunks)
  • apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControl/components/AccessControlCreate/AccessControlCreate.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControl/components/AccessControlUpdate/AccessControlUpdate.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
📓 Learnings (1)
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)
Learnt from: birkirkristmunds
PR: island-is/island.is#17109
File: apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx:336-360
Timestamp: 2024-12-10T15:10:49.998Z
Learning: In the `RecyclingCompanyForm` component (`apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx`), the `isMunicipality` checkbox must remain in the DOM for all users since its value is stored in the database. However, only users with the developer role can manipulate it through the UI. This ensures that the checkbox value is maintained correctly while restricting interaction to authorized users.
🔇 Additional comments (8)
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (2)

Line range hint 1-48: LGTM! Well-structured imports and interface updates

The new imports and interface changes are well-organized and properly typed. The optional isMunicipalityPage property with its default value follows TypeScript best practices.


379-380: LGTM! Improved button semantics

The button changes from 'arrowForward' to 'save' icon and updated text provide better clarity about the action being performed.

apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts (3)

22-27: Method name should match GraphQL query name

The method name getAllRecyclingPartners doesn't match the GraphQL query name skilavottordAllRecyclingPartners. This can lead to confusion during maintenance.

 @Query(() => [RecyclingPartnerModel], {
   name: 'skilavottordAllRecyclingPartners',
 })
-async getAllRecyclingPartners(): Promise<RecyclingPartnerModel[]> {
+async skilavottordAllRecyclingPartners(): Promise<RecyclingPartnerModel[]> {
   return this.recyclingPartnerService.findAll()
 }

32-45: Add input validation and error handling

The method should validate inputs and include proper error handling.

 async getRecyclingPartners(
   @Args('isMunicipalityPage', { type: () => Boolean, nullable: true })
   isMunicipalityPage: boolean,
   @Args('municipalityId', { type: () => String, nullable: true })
   municipalityId: string | null,
 ): Promise<RecyclingPartnerModel[]> {
+  if (municipalityId && !municipalityId.trim()) {
+    throw new BadRequestException('municipalityId cannot be empty')
+  }
+  try {
     return this.recyclingPartnerService.findRecyclingPartners(
       isMunicipalityPage,
       municipalityId,
     )
+  } catch (error) {
+    throw new InternalServerErrorException(
+      `Failed to fetch recycling partners: ${error.message}`,
+    )
+  }
 }

20-20: Verify the municipality role permissions across the application

The addition of Role.municipality to multiple endpoints needs verification to ensure proper access control implementation.

Also applies to: 30-30, 55-55, 66-66, 87-87

✅ Verification successful

Let me gather more information about the authorization implementation to ensure proper role handling.


Let me check the authorization guard implementation to verify how the municipality role is handled.


Role.municipality authorization is properly implemented

The municipality role has been consistently implemented across the application:

  • Correctly defined in the Role enum (apps/skilavottord/ws/src/app/modules/auth/user.model.ts)
  • Properly used in @authorize decorators across multiple resolvers
  • Specific handling in the recyclingPartner service for municipality-specific queries
  • Access control is consistently applied in related modules (vehicle, recyclingPartner, accessControl)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistent role implementation and guard usage

# Check for Role.municipality usage
rg -A 2 "Role\.municipality" 

# Check for proper guard implementation
ast-grep --pattern 'class $_ implements CanActivate {
  $$$
  Role.municipality
  $$$
}'

Length of output: 5947


Script:

#!/bin/bash
# Check for the authorization guard implementation
ast-grep --pattern 'class AuthorizeGuard implements CanActivate {
  $$$
}'

# Check for role enum definition
rg -A 5 "export enum Role"

# Check for any custom municipality-specific guards
rg -l "municipality.*guard"

Length of output: 30419


Script:

#!/bin/bash
# Check for the authorization guard implementation
rg -A 10 "class.*Authorize.*Guard" 

# Check for municipality-specific authorization logic
rg -A 5 "canActivate.*municipality"

# Check for the Authorize decorator implementation
ast-grep --pattern '@Authorize({
  $$$
})'

Length of output: 5084

apps/skilavottord/web/screens/AccessControl/components/AccessControlUpdate/AccessControlUpdate.tsx (2)

91-94: Duplicate: Handle potential undefined role in partnerIdRequired

When using watch('role')?.value, ensure that watch('role') doesn't return undefined before accessing .value. Consider setting a default value or adding additional null checks.


57-60: Verify municipality mapping logic

The code assumes that municipality's companyId matches the recyclingPartner's companyId. This might lead to incorrect municipality assignments if the IDs don't match.

✅ Verification successful

Let me gather more information about the municipality and recycling partner data structures to verify this relationship.


Let me check one more thing to understand how the recycling partners are structured and their relationship with municipalities.


Based on the gathered evidence, I can now provide the final response:

The municipality mapping logic is correct and safe

The code correctly maps recycling partners to municipalities. The evidence shows that:

  1. The skilavottordRecyclingPartners query includes municipality relationships and is used consistently across the codebase
  2. The mapping between companyId and municipalities is handled properly in the RecyclingCompanyForm component, establishing the correct relationship
  3. The same pattern is used in both AccessControl components, ensuring consistency
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if municipality and recycling partner IDs match the assumed pattern
ast-grep --pattern 'companyId: string' # Search for company ID type definitions
rg -A 2 'municipality.*companyId|recyclingPartner.*companyId' # Search for ID usage patterns

Length of output: 2324


Script:

#!/bin/bash
# Check municipality and recycling partner type definitions and data transformations
ast-grep --pattern 'interface Municipality {
  $$$
}'

ast-grep --pattern 'interface RecyclingPartner {
  $$$
}'

# Check how municipalities are mapped in the codebase
rg -A 3 'municipalities.*map' 

Length of output: 4958


Script:

#!/bin/bash
# Check recycling partner data structure and municipality relationships
ast-grep --pattern 'type RecyclingPartnerDTO = {
  $$$
}'

# Look for municipality-recycling partner relationship definitions
rg -A 3 'skilavottordRecyclingPartners'

Length of output: 2896

apps/skilavottord/web/screens/AccessControl/components/AccessControlCreate/AccessControlCreate.tsx (1)

50-62: ⚠️ Potential issue

Improve error handling in getPartnerId function

The function needs additional safeguards:

  1. Missing null check for user?.partnerId
  2. No error handling for invalid role combinations
 const getPartnerId = (
-  municipalityId: string,
-  partnerId: string,
+  municipalityId: string | null | undefined,
+  partnerId: string | null | undefined,
   role: Role,
 ) => {
+  if (!user) {
+    throw new Error('User context is required')
+  }
+
   // If the user has municipality role, then he can only create a new access under the same municipality
   if (hasMunicipalityRole(user?.role) && hasMunicipalityRole(role)) {
-    return user.partnerId
+    return user.partnerId ?? null
   }

   // If selected role is municipality, use municipalityId, else use partnerId
-  return hasMunicipalityRole(role) ? municipalityId : partnerId || null
+  return hasMunicipalityRole(role) ? municipalityId ?? null : partnerId ?? null
 }

Likely invalid or redundant comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
apps/skilavottord/web/screens/AccessControl/components/AccessControlUpdate/AccessControlUpdate.tsx (1)

97-100: ⚠️ Potential issue

Add null check for role value

The role value check should handle undefined cases.

       partnerIdRequired={
-        watch('role')?.value === Role.recyclingCompanyAdmin ||
-        watch('role')?.value === Role.recyclingCompany
+        (watch('role')?.value === Role.recyclingCompanyAdmin ||
+         watch('role')?.value === Role.recyclingCompany) ?? false
       }
🧹 Nitpick comments (15)
apps/skilavottord/web/utils/accessUtils.ts (3)

4-9: Add JSDoc documentation for better type information and usage guidance.

The function signature is well-typed, but adding JSDoc would improve developer experience by documenting parameter requirements and return values.

+/**
+ * Determines the appropriate partner ID based on user role and provided parameters
+ * @param user - The current user object
+ * @param municipalityId - The ID of the municipality if applicable
+ * @param partnerId - The partner ID if applicable
+ * @param role - The role being evaluated
+ * @returns The determined partner ID or null
+ */
 export const getPartnerId = (
   user: SkilavottordUser | undefined,
   municipalityId: string | null,
   partnerId: string | null,
   role: Role,
 ) => {

10-13: Consider making the role check more explicit.

The conditional logic is correct, but the comment could be more precise about the business rule being enforced.

-  // If the user has municipality role, then he can only create a new access under the same municipality
+  // Municipality users can only create access within their assigned municipality
   if (hasMunicipalityRole(user?.role) && hasMunicipalityRole(role)) {
     return user.partnerId
   }

15-17: Consider making null coalescing more explicit with early returns.

The ternary with null coalescing could be more readable with explicit conditions.

-  return hasMunicipalityRole(role) ? municipalityId ?? null : partnerId ?? null
+  if (hasMunicipalityRole(role)) {
+    return municipalityId ?? null
+  }
+  return partnerId ?? null
apps/skilavottord/web/screens/AccessControl/components/AccessControlCreate/AccessControlCreate.tsx (1)

85-89: Simplify the partnerIdRequired logic

The current implementation can be made more concise and readable.

-      partnerIdRequired={
-        (watch('role')?.value === Role.recyclingCompanyAdmin ||
-          watch('role')?.value === Role.recyclingCompany) ??
-        false
-      }
+      partnerIdRequired={[Role.recyclingCompanyAdmin, Role.recyclingCompany].includes(watch('role')?.value ?? '')}
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts (1)

81-96: Enhance JSDoc documentation

While the implementation is good, the JSDoc comments could be more descriptive.

   /**
    * Get the id of the municipality or recyclingpartner that is paying for the recycling request
-   * @param companyId
-   * @returns
+   * @param {string} companyId - The unique identifier of the company
+   * @returns {Promise<string>} The ID of the paying partner (municipality or recycling partner)
+   * @throws {Error} When no partner is found for the given company ID
    */
apps/skilavottord/web/screens/AccessControl/components/AccessControlUpdate/AccessControlUpdate.tsx (1)

61-64: Simplify municipality ID lookup

The find logic can be made more concise.

-      municipalityId: municipalities.find(
-        (option) =>
-          option.value === currentPartner?.recyclingPartner?.companyId,
-      ),
+      municipalityId: municipalities.find(option => option.value === currentPartner?.recyclingPartner?.companyId),
apps/skilavottord/web/i18n/locales/en.json (2)

395-396: Consider more descriptive button labels.

The "view" label could be more descriptive. Consider using "View details" or "View company" to provide more context to users.


647-662: Enhance descriptive text for municipality management.

Consider adding more context to the following strings:

  • Add a description of what municipalities are used for in the system
  • Clarify the impact of adding/updating municipalities
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts (1)

37-56: Add parameter documentation and validation

While the implementation looks good, consider these improvements:

  1. Add JSDoc comments to document the parameters and their relationship
  2. Add validation for the case when municipalityId is provided
 @Query(() => [RecyclingPartnerModel], {
   name: 'skilavottordRecyclingPartners',
 })
+/**
+ * Retrieves recycling partners based on municipality page status and ID
+ * @param isMunicipalityPage - Whether to fetch municipality-specific partners
+ * @param municipalityId - Optional municipality ID, can be null for recyclingFund role
+ */
 async skilavottordRecyclingPartners(
   @Args('isMunicipalityPage', { type: () => Boolean, nullable: true })
   isMunicipalityPage: boolean,
   @Args('municipalityId', { type: () => String, nullable: true })
   municipalityId: string | null,
 ): Promise<RecyclingPartnerModel[]> {
   try {
+    if (municipalityId && !isMunicipalityPage) {
+      throw new BadRequestException(
+        'municipalityId can only be provided when isMunicipalityPage is true',
+      )
+    }
     return this.recyclingPartnerService.findRecyclingPartners(
       isMunicipalityPage,
       municipalityId,
     )
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (2)

15-19: Consider grouping related auth imports

The auth-related imports (hasPermission, hasMunicipalityRole) could be combined into a single import statement for better organization.

-import {
-  hasPermission,
-  hasMunicipalityRole,
-} from '@island.is/skilavottord-web/auth/utils'
+import { hasPermission, hasMunicipalityRole } from '@island.is/skilavottord-web/auth/utils'

161-161: Consider alternative to delete operator

Using the delete operator can impact performance. Consider using undefined assignment instead.

-delete input.__typename
+input.__typename = undefined
🧰 Tools
🪛 Biome (1.9.4)

[error] 161-161: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

apps/skilavottord/ws/src/app/modules/vehicle/vehicle.service.ts (3)

26-27: Add explicit type annotation for better type safety

The partnerIds variable should have an explicit type annotation to prevent potential type-related issues.

-    let partnerIds = []
+    let partnerIds: string[] | null = []

28-48: Improve comment clarity for municipality partner handling

The implementation looks good with proper error handling and query optimization. However, the comments could be more descriptive.

-    // Get all sub recycling partners of the municipality
-    // else get all
+    // If partnerId is provided, fetch all sub-recycling partners associated with the municipality
+    // Otherwise, return null to fetch all partners

61-64: Fix indentation for better readability

The object spread operator's indentation is inconsistent with the surrounding code.

             ...(partnerIds
               ? {
-                  recyclingPartnerId: partnerIds,
+                recyclingPartnerId: partnerIds,
                }
               : {}),
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (1)

122-130: Refactor duplicated success handling

The success handling contains duplicated toast message code.

Apply this diff to reduce code duplication:

if (!errors) {
-  if (isMunicipalityPage) {
-    router.push(routes.municipalities.baseRoute).then(() => {
-      toast.success(t.recyclingCompany.add.added)
-    })
-  } else {
-    router.push(routes.recyclingCompanies.baseRoute).then(() => {
-      toast.success(t.recyclingCompany.add.added)
-    })
-  }
+  const route = isMunicipalityPage
+    ? routes.municipalities.baseRoute
+    : routes.recyclingCompanies.baseRoute
+  router.push(route).then(() => {
+    toast.success(t.recyclingCompany.add.added)
+  })
}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7e4ddbb and 4336424.

📒 Files selected for processing (21)
  • apps/skilavottord/web/i18n/locales/en.json (5 hunks)
  • apps/skilavottord/web/i18n/locales/is.json (6 hunks)
  • apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (12 hunks)
  • apps/skilavottord/web/screens/AccessControl/components/AccessControlCreate/AccessControlCreate.tsx (5 hunks)
  • apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx (4 hunks)
  • apps/skilavottord/web/screens/AccessControl/components/AccessControlUpdate/AccessControlUpdate.tsx (6 hunks)
  • apps/skilavottord/web/screens/Overview/Overview.tsx (1 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (5 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (7 hunks)
  • apps/skilavottord/web/screens/RecyclingFund/Overview/Overview.tsx (4 hunks)
  • apps/skilavottord/web/utils/accessUtils.ts (1 hunks)
  • apps/skilavottord/web/utils/index.ts (1 hunks)
  • apps/skilavottord/web/utils/roleUtils.ts (1 hunks)
  • apps/skilavottord/ws/migrations/202412013210715-addcolumns-recycling-partners-municipality.js (1 hunks)
  • apps/skilavottord/ws/src/app/modules/accessControl/accessControl.resolver.ts (2 hunks)
  • apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.input.ts (2 hunks)
  • apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts (4 hunks)
  • apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts (3 hunks)
  • apps/skilavottord/ws/src/app/modules/recyclingRequest/recyclingRequest.service.ts (4 hunks)
  • apps/skilavottord/ws/src/app/modules/vehicle/vehicle.resolver.ts (1 hunks)
  • apps/skilavottord/ws/src/app/modules/vehicle/vehicle.service.ts (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/skilavottord/web/screens/Overview/Overview.tsx
🚧 Files skipped from review as they are similar to previous changes (5)
  • apps/skilavottord/ws/migrations/202412013210715-addcolumns-recycling-partners-municipality.js
  • apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.input.ts
  • apps/skilavottord/web/screens/RecyclingFund/Overview/Overview.tsx
  • apps/skilavottord/ws/src/app/modules/recyclingRequest/recyclingRequest.service.ts
  • apps/skilavottord/ws/src/app/modules/vehicle/vehicle.resolver.ts
👮 Files not reviewed due to content moderation or server errors (3)
  • apps/skilavottord/ws/src/app/modules/accessControl/accessControl.resolver.ts
  • apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx
  • apps/skilavottord/web/screens/AccessControl/AccessControl.tsx
🧰 Additional context used
📓 Path-based instructions (15)
apps/skilavottord/web/utils/index.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/utils/accessUtils.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/utils/roleUtils.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/vehicle/vehicle.service.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/accessControl/accessControl.resolver.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/i18n/locales/en.json (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControl/components/AccessControlCreate/AccessControlCreate.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControl/components/AccessControlUpdate/AccessControlUpdate.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/i18n/locales/is.json (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
📓 Learnings (2)
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts (1)
Learnt from: birkirkristmunds
PR: island-is/island.is#17109
File: apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts:32-45
Timestamp: 2024-12-16T12:25:52.236Z
Learning: In `apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts`, the `municipalityId` parameter in `getRecyclingPartners` can be `null` for users with the `recyclingFund` role.
apps/skilavottord/web/i18n/locales/is.json (1)
Learnt from: birkirkristmunds
PR: island-is/island.is#17109
File: apps/skilavottord/web/i18n/locales/is.json:0-0
Timestamp: 2024-12-16T12:38:27.802Z
Learning: In the Skilavottord web application, the form for recycling partners is reused for municipalities. Therefore, specific translations for municipalities' form inputs are not needed in `apps/skilavottord/web/i18n/locales/is.json`.
🪛 Biome (1.9.4)
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx

[error] 161-161: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

🔇 Additional comments (21)
apps/skilavottord/web/utils/index.ts (1)

5-5: LGTM! Export statement follows established pattern.

The new export follows the same pattern as other utility exports and maintains consistency in the barrel file structure.

apps/skilavottord/web/utils/roleUtils.ts (1)

18-19: Verify translation completeness across the application.

The municipality role translations are properly added. However, we should verify that these translations are consistently used across all relevant components.

✅ Verification successful

Translations for municipality role are consistent across the application

The verification shows that:

  • All necessary translations for "Municipality"/"Sveitarfélag" are properly defined in both English (en.json) and Icelandic (is.json) locale files
  • The Role.municipality usage is consistent across components, particularly in:
    • AccessControl components for role checks
    • AccessControlModal for role-specific logic
    • roleUtils.ts for translation handling
    • auth/utils.ts for role verification
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistency in municipality translations across the application

# Search for municipality-related translations in locale files
echo "Checking locale files for municipality translations..."
rg -i "municipality|sveitarfélag" apps/skilavottord/web/i18n/locales/

# Search for municipality role usage in components
echo "Checking components for municipality role usage..."
rg "Role\.municipality" apps/skilavottord/web/

Length of output: 4368

apps/skilavottord/web/screens/AccessControl/components/AccessControlCreate/AccessControlCreate.tsx (1)

68-71: LGTM! Good form reset implementation

The useEffect hook correctly resets the form when the modal is re-opened, with proper dependency array.

apps/skilavottord/web/i18n/locales/en.json (2)

368-372: LGTM: Navigation items for municipality management added correctly.

The new navigation items for municipality management are properly structured and consistent with the application's navigation pattern.


641-645: LGTM: Municipality routes added with consistent pattern.

The new routes for municipality management follow the established pattern used for other sections.

apps/skilavottord/web/i18n/locales/is.json (4)

368-372: LGTM: Municipality navigation items properly translated.

The Icelandic translations for municipality navigation items are accurate and consistent with the English version.


587-592: LGTM: Municipality field properly added to access control.

The municipality field in the access control section is properly structured with consistent validation rules.


646-650: LGTM: Municipality routes properly added.

The routes for municipality management are properly structured and consistent with other sections.


659-659: ⚠️ Potential issue

Fix incorrect entity reference in municipality view.

The info text incorrectly refers to "móttökuaðila" (recycling company) instead of "sveitarfélag" (municipality).

Apply this fix:

-"info": "Þú getur annaðhvort uppfært eða eytt móttökuaðila. Vinsamlegast staðfestið að upplýsingar fyrirtækis séu rétt slegnar inn.",
+"info": "Þú getur annaðhvort uppfært eða eytt sveitarfélagi. Vinsamlegast staðfestið að upplýsingar sveitarfélags séu rétt slegnar inn.",

Likely invalid or redundant comment.

apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts (3)

1-6: LGTM: Appropriate error handling imports

The added imports from @nestjs/common provide the necessary error types for proper error handling throughout the resolver.


27-31: Maintain consistent method naming convention

The method name doesn't match the GraphQL query name pattern. The query uses the 'skilavottord' prefix while the method name doesn't.

 @Query(() => [RecyclingPartnerModel], {
   name: 'skilavottordAllRecyclingPartners',
 })
-async getAllRecyclingPartners(): Promise<RecyclingPartnerModel[]> {
+async skilavottordAllRecyclingPartners(): Promise<RecyclingPartnerModel[]> {

25-25: Verify role-based access control implementation

The addition of Role.municipality to authorized roles is consistent across all methods. However, we should verify the implementation of this role in the auth module and any UI components that use these endpoints.

Also applies to: 66-66, 77-77, 98-98

✅ Verification successful

Role.municipality implementation is properly integrated

The verification shows that the Role.municipality is:

  • Correctly defined in the Role enum
  • Consistently applied across all methods in recyclingPartner.resolver.ts
  • Properly integrated in other resolvers and services with appropriate access controls
  • Used in logical branching for specific municipality-related functionality

The implementation is complete and consistent with the codebase's role-based access control system.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify role implementation and usage

# Check role definition
echo "Checking Role enum definition..."
rg -A 5 "export enum Role" apps/skilavottord/ws/src/app

# Check auth guard implementation
echo "Checking auth guard implementation..."
rg -A 10 "canActivate.*Role.municipality" apps/skilavottord/ws/src/app

# Check UI components using these endpoints
echo "Checking UI components..."
rg -A 5 "skilavottordRecyclingPartners|skilavottordAllRecyclingPartners" apps/skilavottord/web/src

Length of output: 1050


Script:

#!/bin/bash
# Let's verify the role implementation more thoroughly

# Check if municipality role is defined in the Role enum
echo "Checking Role enum for municipality..."
rg -p "municipality.*=.*'municipality'" apps/skilavottord/ws/src/app

# Check all usages of Role.municipality in the codebase
echo "Checking Role.municipality usage..."
rg -p "Role\.municipality" apps/skilavottord/ws/src/app

# Check auth guards and decorators
echo "Checking auth guards and decorators..."
rg -p "@UseGuards|@Roles" apps/skilavottord/ws/src/app/modules

# Check recyclingPartner resolver for role consistency
echo "Checking recyclingPartner resolver..."
rg -p "roles.*:.*\[.*\]" apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts

Length of output: 2450

apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (3)

152-157: LGTM! Clean implementation of navigation logic

The extracted navigation function improves code maintainability by removing duplication, as suggested in previous reviews.


163-167: LGTM! Robust type handling for municipalityId

The implementation follows the suggested approach from previous reviews for safer type handling.


87-91: Verify role-based access control implementation

The municipality role check is crucial for security. Let's verify that this implementation correctly restricts access.

✅ Verification successful

Let me analyze the role-based access control implementation further by checking the actual implementation of hasMunicipalityRole.


Based on the analysis of the code, I can now provide a final response:

Role-based access control implementation is correctly implemented

The implementation is secure and properly restricts access based on municipality roles:

  • The hasMunicipalityRole function is a simple, clear comparison that checks if the user's role exactly matches Role.municipality
  • The Role enum is properly defined with distinct values for different roles including 'municipality'
  • The role check is used consistently across the codebase to restrict access to municipality-specific functionality
  • The partnerId assignment is properly guarded by the role check, ensuring only municipality users can access their specific data
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other instances of hasMunicipalityRole to ensure consistent usage
rg "hasMunicipalityRole" --type ts

# Search for role-based access patterns
ast-grep --pattern 'if ($CONDITION) { $PARTNER_ID = $USER.$FIELD }'

Length of output: 44435


Script:

#!/bin/bash
# Check the implementation of hasMunicipalityRole
ast-grep --pattern 'export const hasMunicipalityRole = $_'

# Check the Role enum definition
rg "enum Role" -A 10 --type ts

Length of output: 65785

apps/skilavottord/ws/src/app/modules/vehicle/vehicle.service.ts (1)

33-36: Verify database index for optimal query performance

The query filtering on municipalityId could benefit from an index to improve performance, especially with large datasets.

✅ Verification successful

Database query performance is adequately optimized

While there isn't a direct index on municipality_id, the current query pattern doesn't require one for optimal performance because:

  1. The table has an index on is_municipality which helps filter recycling partners efficiently
  2. The municipality_id column was recently added (December 2024) and is used in a simple equality filter
  3. The result set is limited to only the companyId attribute, reducing data transfer

The current implementation is sufficient for the expected data volume and query pattern.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if an index exists on the municipalityId column

# Search for index definitions in migration files
fd -e ts -e js . | xargs rg -A 5 "CREATE.*INDEX.*municipalityId"

# Search for Sequelize index definitions
ast-grep --pattern 'index: {
  $$$
  fields: [$$$"municipalityId"$$$]
  $$$
}'

Length of output: 147


Script:

#!/bin/bash
# Let's try a broader search to understand the database schema and existing indexes

# Search for the RecyclingPartner model definition
ast-grep --pattern 'class RecyclingPartnerModel extends Model {
  $$$
}'

# Search for any migrations related to recycling partners
fd -e ts -e js . | xargs rg -B 2 -A 5 "createTable.*recycling.*partner"

# Look for any index definitions in a case-insensitive way
fd -e ts -e js . | xargs rg -i "index.*municipality"

Length of output: 11049


Script:

#!/bin/bash
# Let's check for any migrations related to municipalityId specifically
fd -e ts -e js . | xargs rg -B 2 -A 5 "municipality_id"

# Look for the specific migration file that added the municipality_id column
fd "202412013210715-addcolumns-recycling-partners-municipality.js" . | xargs cat

Length of output: 20304

apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (5)

19-20: LGTM: New components properly imported

The NavigationLinks and PageHeader components are correctly imported from their respective paths.


58-73: LGTM: Clean separation of municipality logic

The code clearly differentiates between municipality and regular recycling company contexts, with proper variable assignments based on the route.


94-95: LGTM: Proper refetch query configuration

The refetch query is correctly configured with the necessary variables for municipality filtering.


143-143: LGTM: Clean component structure and proper prop handling

The component follows NextJS best practices with:

  • Proper layout structure using PartnerPageLayout
  • Clean implementation of PageHeader
  • Correct prop passing to RecyclingCompanyForm

Also applies to: 167-167, 175-175


39-40: Verify GraphQL schema compatibility

The mutation has been updated to include municipality-related fields. Ensure these fields are properly defined in the GraphQL schema.

✅ Verification successful

GraphQL schema compatibility verified

The fields isMunicipality and municipalityId are properly defined in the GraphQL schema through the RecyclingPartnerModel class using @Field decorators. The model shows:

  • isMunicipality is defined as a non-nullable Boolean field
  • municipalityId is defined as a nullable String field

Both fields are properly mapped to the database schema and exposed through GraphQL.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if the new fields are defined in the GraphQL schema
ast-grep --pattern 'type RecyclingPartner {
  $$$
  isMunicipality: Boolean
  municipalityId: String
  $$$
}'

Length of output: 111


Script:

#!/bin/bash
# Let's search for GraphQL schema files and check their content
fd -e graphql -x cat {}

# Also search for type definitions in TypeScript files as they might be using code-first approach
ast-grep --pattern 'type RecyclingPartner'

Length of output: 81450


Script:

#!/bin/bash
# Let's search for RecyclingPartner type definition in TypeScript files
ast-grep --pattern 'interface RecyclingPartner {
  $$$
}'

# Also search for any GraphQL type definitions in .graphql files
fd -e graphql -e ts -x grep -l "RecyclingPartner" {}

# Let's also check for any mutation types that might use these fields
ast-grep --pattern 'mutation $_ {
  $$$
  RecyclingPartner {
    $$$
    isMunicipality
    municipalityId
    $$$
  }
  $$$
}'

Length of output: 2315


Script:

#!/bin/bash
# Let's check the recyclingPartner model and resolver for these fields
cat apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.model.ts
cat apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts

Length of output: 5681

@birkirkristmunds birkirkristmunds added deprecated:automerge (Disabled) Merge this PR as soon as all checks pass deploy-feature Deploys features to dev labels Dec 16, 2024
Copy link
Contributor

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts (3)

33-33: Update comment to match parameter names

The comment references Role.municipality but the parameter is named isMunicipalityPage. Update the comment to match the actual parameter names for better clarity.

-      // If Role.municipality, return all recycling partners that are not municipalities
+      // If municipalityId is provided, return all recycling partners that are not municipalities

28-56: Add input validation and improve error handling

While the implementation is generally good, consider adding input validation and more specific error handling.

   async findRecyclingPartners(
     isMunicipalityPage: boolean,
     municipalityId: string | null | undefined,
   ): Promise<RecyclingPartnerModel[]> {
     try {
+      // Validate municipalityId format if provided
+      if (municipalityId && !/^[A-Za-z0-9-]+$/.test(municipalityId)) {
+        throw new Error('Invalid municipality ID format');
+      }
+
       if (municipalityId) {
         return await this.recyclingPartnerModel.findAll({
           where: {
@@ -53,6 +58,8 @@
         },
       })
     } catch (error) {
+      if (error.name === 'SequelizeConnectionError')
+        throw new Error('Database connection error');
       throw new Error(`Failed to fetch recycling partners: ${error.message}`)
     }
   }

85-100: Enhance type safety with type narrowing

The implementation is good, but we can improve type safety.

   async getPayingPartnerId(companyId: string): Promise<string> {
+    if (!companyId?.trim()) {
+      throw new Error('Company ID is required');
+    }
+
     const partner = await this.recyclingPartnerModel.findOne({
       where: { companyId },
     })

     if (!partner) {
       throw new Error(`Partner not found for company ID: ${companyId}`)
     }

+    // Ensure both values are strings before using nullish coalescing
+    const municipalityId = partner.municipalityId?.toString();
+    const partnerCompanyId = partner.companyId?.toString();
+
+    if (!municipalityId && !partnerCompanyId) {
+      throw new Error('Invalid partner data: missing both municipalityId and companyId');
+    }
+
-    return partner.municipalityId ?? partner.companyId
+    return municipalityId ?? partnerCompanyId;
   }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5985196 and 3eb50de.

📒 Files selected for processing (4)
  • apps/skilavottord/README.md (2 hunks)
  • apps/skilavottord/web/i18n/locales/is.json (6 hunks)
  • apps/skilavottord/web/i18n/locales/locales.spec.ts (2 hunks)
  • apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts (3 hunks)
✅ Files skipped from review due to trivial changes (2)
  • apps/skilavottord/web/i18n/locales/locales.spec.ts
  • apps/skilavottord/README.md
🧰 Additional context used
📓 Path-based instructions (2)
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/i18n/locales/is.json (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
📓 Learnings (1)
apps/skilavottord/web/i18n/locales/is.json (1)
Learnt from: birkirkristmunds
PR: island-is/island.is#17109
File: apps/skilavottord/web/i18n/locales/is.json:0-0
Timestamp: 2024-12-16T12:38:27.802Z
Learning: In the Skilavottord web application, the form for recycling partners is reused for municipalities. Therefore, specific translations for municipalities' form inputs are not needed in `apps/skilavottord/web/i18n/locales/is.json`.
🔇 Additional comments (5)
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts (1)

9-9: LGTM!

The Sequelize Op import is correctly placed and necessary for the logical operations in the new methods.

apps/skilavottord/web/i18n/locales/is.json (4)

368-372: LGTM! Navigation translations are well-structured.

The new municipality-related navigation items are properly integrated into the existing structure.


587-592: LGTM! Access control translations are complete and consistent.

The municipality field in the access control modal follows the established pattern for validation rules and translations.


646-650: LGTM! Route definitions are well-structured.

The municipality routes follow the established pattern and include all necessary paths.


486-489: ⚠️ Potential issue

Fix validation message format inconsistency.

The validation message format for the municipality field is inconsistent with other fields.

Apply this fix:

  "municipality": {
    "label": "Sveitarfélag",
    "placeholder": "Sveitarfélag",
-   "required": "Skylda er að fylla út sveitarfélag"
+   "rules": {
+     "required": "Skylda er að fylla út sveitarfélag"
+   }
  }

Likely invalid or redundant comment.

apps/skilavottord/web/i18n/locales/is.json Outdated Show resolved Hide resolved
- Fix after code rabbit review
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
apps/skilavottord/web/screens/RecyclingFund/Overview/components/CarsTable/CarsTable.tsx (1)

30-50: Consider optimizing nested map operations.

While the implementation has been improved with proper key uniqueness and null handling, the nested map operations could impact performance with large datasets.

Consider these optimizations:

+ const memoizedRequests = useMemo(() => 
    vehicles.flatMap(({ vehicleId, vehicleType, newregDate, recyclingRequests }) =>
      recyclingRequests?.map(({ createdAt, nameOfRequestor, recyclingPartner }, index) => ({
        key: `${vehicleId}-${index}`,
        vehicleId,
        vehicleType,
        modelYear: getYear(newregDate),
        deregistrationDate: getDate(createdAt),
        nameOfRequestor,
        companyName: recyclingPartner?.municipality?.companyName ?? nameOfRequestor
      })) ?? []
    ),
+  [vehicles]
+ )

  return (
    <Table>
      <Head>{/* ... */}</Head>
      <Body>
-       {vehicles.map(
-         ({ vehicleId, vehicleType, newregDate, recyclingRequests }) => {
-           return recyclingRequests?.map(
-             ({ createdAt, nameOfRequestor, recyclingPartner }, index) => {
-               const modelYear = getYear(newregDate)
-               const deregistrationDate = getDate(createdAt)
+       {memoizedRequests.map(({
+         key,
+         vehicleId,
+         vehicleType,
+         modelYear,
+         deregistrationDate,
+         nameOfRequestor,
+         companyName
+       }) => (
                return (
-                 <Row key={`${vehicleId}-${index}`}>
+                 <Row key={key}>
                    <Data>
                      <Text variant="eyebrow">{vehicleId}</Text>
                    </Data>
                    <Data>{vehicleType}</Data>
                    <Data>{modelYear ?? ''}</Data>
                    <Data>{nameOfRequestor}</Data>
                    <Data>
-                     {recyclingPartner?.municipality?.companyName ??
-                       nameOfRequestor}
+                     {companyName}
                    </Data>
                    <Data>{deregistrationDate ?? ''}</Data>
                  </Row>
                )
-             },
-           )
-         },
-       )}
+       ))}
      </Body>
    </Table>
  )

This optimization:

  1. Flattens the nested maps into a single operation
  2. Memoizes the data transformation
  3. Simplifies the JSX rendering logic
  4. Maintains all the null checks and fallbacks
apps/skilavottord/ws/migrations/202412230017109-add-view-municipality.js (1)

2-9: Consider using "CREATE OR REPLACE VIEW" for seamless updates and versioning.

Currently, you are using "CREATE VIEW" to introduce the municipality_view, which will fail if the view already exists. If you expect to update or modify this view in future migrations or if the view might exist from earlier iterations, you could use "CREATE OR REPLACE VIEW" to avoid errors during deployment.

apps/skilavottord/ws/migrations/202412010017109-addcolumns-recycling-partners-municipality.js (2)

5-9: Column addition for is_municipality seems correct.

The column name, type, and default value are suitably configured. Consider verifying if “is_municipality” follows your naming conventions for boolean fields throughout your codebase.


10-13: Consider foreign key constraints.

Adding the “municipality_id” column as a string is fine, but if you have a separate municipality table, a foreign key constraint could help maintain referential integrity.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between abd46a4 and 7cb4964.

📒 Files selected for processing (3)
  • apps/skilavottord/web/screens/RecyclingFund/Overview/components/CarsTable/CarsTable.tsx (2 hunks)
  • apps/skilavottord/ws/migrations/202412010017109-addcolumns-recycling-partners-municipality.js (1 hunks)
  • apps/skilavottord/ws/migrations/202412230017109-add-view-municipality.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
apps/skilavottord/web/screens/RecyclingFund/Overview/components/CarsTable/CarsTable.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/migrations/202412010017109-addcolumns-recycling-partners-municipality.js (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/migrations/202412230017109-add-view-municipality.js (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
🔇 Additional comments (7)
apps/skilavottord/web/screens/RecyclingFund/Overview/components/CarsTable/CarsTable.tsx (3)

1-4: LGTM! Clean and well-organized imports.

The imports follow NextJS best practices and include proper TypeScript types.


Line range hint 6-9: LGTM! Well-defined TypeScript interface.

The interface is clear, properly typed, and follows TypeScript best practices.


Line range hint 11-29: LGTM! Clean component structure.

The component follows React and TypeScript best practices, with proper typing and efficient table header implementation.

apps/skilavottord/ws/migrations/202412230017109-add-view-municipality.js (1)

11-15: Migration reversal logic looks good.

Using "DROP VIEW IF EXISTS" is a safe approach to avoid breaking migrations if the view has already been removed, or does not exist. This is a recommended way to gracefully handle reversals. No further action needed.

apps/skilavottord/ws/migrations/202412010017109-addcolumns-recycling-partners-municipality.js (3)

1-2: Looks good.

Importing DataTypes from sequelize is standard for defining column types in a migration.


3-4: Module export is coherent.

Exporting the up/down methods aligns with typical Sequelize migration patterns.


14-16: Index creation is sensible.

Indexing “is_municipality” may improve query performance. Verify usage patterns to ensure this index is beneficial.

✅ Verification successful

Let me search for usage patterns of the is_municipality column to verify if the index would be beneficial.


Let me search for any queries or service methods that might be filtering or searching by this column to better understand its usage patterns.


Based on the search results, I can now provide a final response about the index's usefulness:

Index on is_municipality is beneficial for query performance

The codebase shows frequent filtering on the is_municipality column in several critical scenarios:

  • Used in a dedicated view municipality_view that filters by is_municipality = true
  • Frequently used in service layer queries to filter recycling partners:
    • To find all municipalities (where: { isMunicipality: true })
    • To find non-municipality partners (where: { isMunicipality: false })
    • In complex OR conditions ([Op.or]: [{ isMunicipality: false }, { isMunicipality: null }])
  • Used in UI components to separate municipality and non-municipality partners
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for SQL queries or ORM operations involving is_municipality
rg -i "is_municipality" --type sql --type js --type ts -A 3 -B 3

Length of output: 4498


Script:

#!/bin/bash
# Search for any service methods or queries using isMunicipality
rg -i "isMunicipality|where.*municipality" --type ts --type js -A 5 -B 5

Length of output: 57679

- Added municipality service
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (7)
apps/skilavottord/ws/src/app/modules/municipality/municipality.service.ts (2)

1-3: Ensure consistent import order and structure.

While importing from NestJS and Sequelize is acceptable, it's beneficial to follow a defined convention (e.g., third-party imports, local imports) to enhance readability and maintainability. This is a minor preference rather than a strict requirement.


13-15: Use a consistent async/await pattern.

Since return await this.municipalityModel.findAll() is simply returning a promise, you can safely drop the await, returning the promise directly. Returning the promise would also keep the code clean.

Proposed change:

-    return await this.municipalityModel.findAll()
+    return this.municipalityModel.findAll()
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (2)

128-152: Consider enhancing error handling for GraphQL queries

While the implementation of lazy queries is good for controlled data fetching, the error handling could be improved. Currently, errors are only used in the loading state check.

Consider implementing proper error handling and user feedback:

+ const handleQueryError = (error: ApolloError) => {
+   // Add your error handling logic here, e.g., showing a toast message
+   console.error('Query failed:', error.message)
+ }

  const [getAllRecyclingPartner, { data: recyclingPartnerData, error: recyclingPartnerError }] = 
    useLazyQuery<Query>(SkilavottordAllRecyclingPartnersQuery, {
    ssr: false,
+   onError: handleQueryError
  })

279-285: Consider handling loading state for modal data

While the implementation correctly fetches data based on user role, it doesn't handle the loading state before showing the modal.

Consider implementing a loading state:

  const handleCreateAccessControlOpenModal = () => {
+   setIsLoading(true)
    if (hasMunicipalityRole(user?.role)) {
-     getAllRecyclingPartnersByMunicipality()
+     getAllRecyclingPartnersByMunicipality().finally(() => setIsLoading(false))
    } else {
-     getAllRecyclingPartner()
+     getAllRecyclingPartner().finally(() => setIsLoading(false))
    }
    setIsCreateAccessControlModalVisible(true)
  }
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (3)

Line range hint 1-35: Consider organizing imports for better maintainability

The imports could be better organized into logical groups:

  • React and related types
  • External libraries (Apollo, kennitala)
  • UI components
  • Internal utilities and types
 import * as kennitala from 'kennitala'
-import React, { BaseSyntheticEvent, FC, useContext } from 'react'
-import { Control, Controller, FieldError } from 'react-hook-form'
-import { FieldValues } from 'react-hook-form/dist/types'
-import { DeepMap } from 'react-hook-form/dist/types/utils'
-import { gql, useQuery } from '@apollo/client'
+// React and types
+import React, { BaseSyntheticEvent, FC, useContext } from 'react'
+import { Control, Controller, FieldError } from 'react-hook-form'
+import { FieldValues } from 'react-hook-form/dist/types'
+import { DeepMap } from 'react-hook-form/dist/types/utils'
+
+// External libraries
+import { gql, useQuery } from '@apollo/client'
+
+// UI Components
 import {
   Box,
   Button,
   Checkbox,
   GridColumn,
   GridContainer,
   GridRow,
   Select,
   Stack,
 } from '@island.is/island-ui/core'
+
+// Internal utilities and types
 import { InputController } from '@island.is/shared/form-fields'
 import {
   hasDeveloperRole,
   hasMunicipalityRole,
 } from '@island.is/skilavottord-web/auth/utils'

38-45: Add TypeScript types for GraphQL query response

Consider adding TypeScript types for the query response to improve type safety and developer experience.

interface Municipality {
  companyId: string;
  companyName: string;
}

interface AllMunicipalitiesResponse {
  skilavottordAllMunicipalities: Municipality[];
}

export const SkilavottordAllMunicipalitiesQuery = gql`
  query skilavottordAllMunicipalitiesQuery {
    skilavottordAllMunicipalities {
      companyId
      companyName
    }
  }
`

347-372: Consider using styled components instead of inline styles

While the implementation correctly maintains the checkbox in the DOM as per requirements, the visibility control could be improved.

-<div
-  style={{
-    display: user?.role && hasDeveloperRole(user.role) ? 'block' : 'none',
-  }}
->
+<Box
+  display={user?.role && hasDeveloperRole(user.role) ? 'block' : 'none'}
+>
   <GridRow>
     {/* ... checkbox implementation ... */}
   </GridRow>
-</div>
+</Box>
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7cb4964 and f17ae44.

📒 Files selected for processing (18)
  • apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (12 hunks)
  • apps/skilavottord/web/screens/AccessControl/components/AccessControlImage/AccessControlImage.tsx (0 hunks)
  • apps/skilavottord/web/screens/AccessControl/components/index.ts (0 hunks)
  • apps/skilavottord/web/screens/AccessControlCompany/components/AccessControlImage/AccessControlImage.tsx (0 hunks)
  • apps/skilavottord/web/screens/AccessControlCompany/components/index.ts (0 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (5 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyImage/RecyclingCompanyImage.tsx (0 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyImage/index.tsx (0 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/components/index.ts (0 hunks)
  • apps/skilavottord/web/screens/RecyclingFund/Overview/components/RecyclingCompanyImage/RecyclingCompanyImage.tsx (0 hunks)
  • apps/skilavottord/web/screens/RecyclingFund/Overview/components/RecyclingCompanyImage/index.tsx (0 hunks)
  • apps/skilavottord/web/screens/RecyclingFund/Overview/components/index.ts (0 hunks)
  • apps/skilavottord/ws/src/app/app.module.ts (2 hunks)
  • apps/skilavottord/ws/src/app/modules/index.ts (1 hunks)
  • apps/skilavottord/ws/src/app/modules/municipality/index.ts (1 hunks)
  • apps/skilavottord/ws/src/app/modules/municipality/municipality.module.ts (1 hunks)
  • apps/skilavottord/ws/src/app/modules/municipality/municipality.resolver.ts (1 hunks)
  • apps/skilavottord/ws/src/app/modules/municipality/municipality.service.ts (1 hunks)
💤 Files with no reviewable changes (10)
  • apps/skilavottord/web/screens/RecyclingCompanies/components/index.ts
  • apps/skilavottord/web/screens/AccessControlCompany/components/index.ts
  • apps/skilavottord/web/screens/AccessControl/components/index.ts
  • apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyImage/index.tsx
  • apps/skilavottord/web/screens/RecyclingFund/Overview/components/index.ts
  • apps/skilavottord/web/screens/RecyclingFund/Overview/components/RecyclingCompanyImage/index.tsx
  • apps/skilavottord/web/screens/AccessControl/components/AccessControlImage/AccessControlImage.tsx
  • apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyImage/RecyclingCompanyImage.tsx
  • apps/skilavottord/web/screens/AccessControlCompany/components/AccessControlImage/AccessControlImage.tsx
  • apps/skilavottord/web/screens/RecyclingFund/Overview/components/RecyclingCompanyImage/RecyclingCompanyImage.tsx
🧰 Additional context used
📓 Path-based instructions (8)
apps/skilavottord/ws/src/app/modules/municipality/index.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/municipality/municipality.module.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/index.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/municipality/municipality.service.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/municipality/municipality.resolver.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/app.module.ts (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
📓 Learnings (1)
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)
Learnt from: birkirkristmunds
PR: island-is/island.is#17109
File: apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx:336-360
Timestamp: 2024-12-10T15:10:49.998Z
Learning: In the `RecyclingCompanyForm` component (`apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx`), the `isMunicipality` checkbox must remain in the DOM for all users since its value is stored in the database. However, only users with the developer role can manipulate it through the UI. This ensures that the checkbox value is maintained correctly while restricting interaction to authorized users.
🔇 Additional comments (17)
apps/skilavottord/ws/src/app/modules/municipality/municipality.service.ts (1)

8-11: Consider validating model injection.

Using @InjectModel(MunicipalityModel) is correct. Just ensure that the corresponding model is registered correctly within the module to avoid potential runtime injection failures. This is typically fine, but verifying that the model is included in your SequelizeModule.forFeature import ensures consistent behavior.

apps/skilavottord/ws/src/app/modules/municipality/municipality.module.ts (2)

1-3: Module naming and structure look appropriate.

This follows NestJS best practices by defining a dedicated feature module for municipality-related functionality.


8-11: Exporting the service is useful for future nesting or shared usage.

Exporting MunicipalityService allows other modules to reuse its logic if necessary. This is aligned with NestJS usage patterns.

apps/skilavottord/ws/src/app/modules/index.ts (1)

10-10: Export statement for MunicipalityModule is straightforward.

This ensures that other parts of the application can import and leverage MunicipalityModule easily.

apps/skilavottord/ws/src/app/modules/municipality/municipality.resolver.ts (5)

1-2: GraphQL imports are correct.

Importing Query and Resolver is standard practice when building a GraphQL resolver with NestJS.


3-4: Authorization import alignment.

Bringing in Authorize and Role from ../auth is consistent with the existing auth setup. Ensure the Authorize() decorator is connected to the roles definitions appropriately.


8-10: Applying @authorize at class level.

Authorizing at the resolver class level helps enforce consistent, higher-level security policies. Further method-level @Authorize usage ensures fine-grained access controls.


13-15: Role-based authorization.

Specifying [Role.developer, Role.recyclingFund, Role.municipality] is clear for restricting municipality-related queries. Confirm that these roles align with overall application requirements (e.g., tie in well with the new municipality role).


19-21: Method naming is clear and descriptive.

skilavottordAllMunicipalities clearly indicates what the query returns. The resolver logic simply delegates to the service, maintaining good separation of concerns.

apps/skilavottord/ws/src/app/app.module.ts (4)

2-2: Neat reorganization of imports.

The addition and reordering of imports here look consistent with NestJS best practices. Everything appears to be correctly referenced without affecting the build.


8-9: Confirm references to renamed Auth module.

Renaming AuthModule to AuthJwtModule clarifies its purpose. Ensure that all consumers using the old module name are updated to avoid runtime errors.


13-20: Validate module dependencies and coverage.

Adding or reordering modules might impact how services and providers are injected. Verify that all modules, especially the new MunicipalityModule, have adequate unit tests and that no existing functionality is broken by the reordering.

Would you like help creating test cases for these modules?


55-55: Good addition of MunicipalityModule.

Adding MunicipalityModule to the import array is correct. Ensure that role-based access for municipality functionality is fully verified.

apps/skilavottord/ws/src/app/modules/municipality/index.ts (1)

1-2: Exports look correct.

Exporting the model and service helps maintain a clear structure. Ensure that other modules or resolvers are exported here as needed for consistent usage across the codebase.

apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (2)

Line range hint 49-56: LGTM: GraphQL query structure aligns with municipality requirements

The SkilavottordAllRecyclingPartnersQuery has been properly updated to include municipality-related fields (municipalityId and isMunicipality).


230-254: LGTM: Clean separation of municipalities and recycling partners

The implementation correctly separates and processes municipalities and recycling partners, with proper sorting and filtering.

apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)

386-387: LGTM! Button updates improve user experience

The changes to the submit button's icon and text better reflect the action being performed.

- Fix after code rabbit review
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (2)

230-254: Consider memoizing filtered partners lists

The filtering and mapping operations on partners are performed on every render. This could impact performance with large datasets.

Consider using useMemo to optimize performance:

+ const recyclingPartners = useMemo(() => 
-  const recyclingPartners = filterInternalPartners(partners)
+   filterInternalPartners(partners)
    .filter((partner) => {
      return !partner.isMunicipality
    })
    .map((partner) => ({
      label: partner.municipalityId
        ? `${partner.municipalityId} - ${partner.companyName}`
        : partner.companyName,
      value: partner.companyId,
    }))
-    .sort((a, b) => a.label.localeCompare(b.label))
+    .sort((a, b) => a.label.localeCompare(b.label)),
+  [partners]
+ )

+ const municipalities = useMemo(() =>
-  const municipalities = filterInternalPartners(partners)
+   filterInternalPartners(partners)
    .filter((partner) => {
      return partner.isMunicipality
    })
    .map((partner) => ({
      label: partner.companyName,
      value: partner.companyId,
    }))
-    .sort((a, b) => a.label.localeCompare(b.label))
+    .sort((a, b) => a.label.localeCompare(b.label)),
+  [partners]
+ )

257-275: Simplify role filtering logic

The role filtering logic can be made more readable and maintainable.

Consider this refactoring:

  const roles = Object.keys(AccessControlRole)
-   .filter((role) =>
-     !hasDeveloperRole(user?.role) ? role !== Role.developer : role,
-   )
-   .filter((role) => {
-     if (hasMunicipalityRole(user?.role)) {
-       return (
-         role === Role.recyclingCompany ||
-         role === Role.recyclingCompanyAdmin ||
-         role === Role.municipality
-       )
-     }
-     return role
-   })
+   .filter((role) => {
+     if (!hasDeveloperRole(user?.role) && role === Role.developer) {
+       return false
+     }
+     if (hasMunicipalityRole(user?.role)) {
+       return [
+         Role.recyclingCompany,
+         Role.recyclingCompanyAdmin,
+         Role.municipality
+       ].includes(role as Role)
+     }
+     return true
+   })
    .map((role) => ({
      label: getRoleTranslation(role as Role, activeLocale),
      value: role,
    }))
    .sort((a, b) => a.label.localeCompare(b.label))
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f17ae44 and 87e8dd6.

📒 Files selected for processing (1)
  • apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (11 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
🔇 Additional comments (2)
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (2)

128-152: LGTM! Well-implemented role-based data fetching

The implementation of lazy queries with proper error handling and loading states is well done. The role-based conditional fetching ensures that users only access data relevant to their role.


413-420: LGTM! Proper data fetching before edit

The implementation correctly fetches the required data based on user role before opening the edit modal.

- Fix after code rabbit review
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (1)
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (1)

Line range hint 77-95: Ensure mutation response matches query structure

The CreateSkilavottordAccessControlMutation response structure is missing fields that are present in the query responses. This inconsistency could lead to cache synchronization issues.

Apply this diff to maintain consistency:

    createSkilavottordAccessControl(input: $input) {
      nationalId
      name
      role
      email
      phone
      partnerId
      recyclingPartner {
        companyId
        companyName
        municipalityId
        isMunicipality
+       active
      }
    }
🧹 Nitpick comments (2)
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (2)

129-153: Enhance error handling for lazy queries

The lazy queries for recycling partners could benefit from error handling callbacks to provide better user feedback.

Consider adding onError callbacks:

  const [getAllRecyclingPartner, { data: recyclingPartnerData, error: recyclingPartnerError, loading: recyclingPartnerLoading }] = useLazyQuery<Query>(SkilavottordAllRecyclingPartnersQuery, {
    ssr: false,
+   onError: (error) => {
+     // Handle error (e.g., show toast notification)
+   }
  })

  const [getAllRecyclingPartnersByMunicipality, { data: recyclingPartnerByIdData, error: recyclingPartnerByIdError, loading: recyclingPartnerByIdLoading }] = useLazyQuery<Query>(SkilavottordRecyclingPartnersQuery, {
    ssr: false,
    variables: {
      isMunicipalityPage: false,
      municipalityId: user?.partnerId,
    },
+   onError: (error) => {
+     // Handle error (e.g., show toast notification)
+   }
  })

231-255: Optimize partner data processing with memoization

The partner filtering and sorting operations are performed on every render. Consider memoizing these operations to improve performance.

Consider using useMemo:

+ const memoizedPartners = useMemo(() => {
    const recyclingPartners = filterInternalPartners(partners)
      .filter((partner) => !partner.isMunicipality)
      .map((partner) => ({
        label: partner.municipalityId
          ? `${partner.municipalityId} - ${partner.companyName}`
          : partner.companyName,
        value: partner.companyId,
      }))
      .sort((a, b) => a.label.localeCompare(b.label))

    const municipalities = filterInternalPartners(partners)
      .filter((partner) => partner.isMunicipality)
      .map((partner) => ({
        label: partner.companyName,
        value: partner.companyId,
      }))
      .sort((a, b) => a.label.localeCompare(b.label))

    return { recyclingPartners, municipalities }
+ }, [partners])
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 87e8dd6 and 04f7ad3.

📒 Files selected for processing (1)
  • apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (11 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
🔇 Additional comments (3)
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (3)

206-213: LGTM! Comprehensive error and loading handling

The error, loading, and data availability checks properly account for all data sources.


258-271: LGTM! Well-structured role filtering

The role filtering logic correctly handles different user roles and permissions, with special consideration for municipality roles.


281-287: LGTM! Proper data prefetching for modals

The modal handlers correctly fetch the appropriate data based on user roles before opening the modals.

- Added sorting
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (2)
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (2)

Line range hint 99-114: Add missing municipality fields to update mutation

The UpdateSkilavottordAccessControlMutation is missing the municipalityId and isMunicipality fields that are present in other queries/mutations. This inconsistency could lead to data loss during updates.

Apply this diff to maintain consistency:

      recyclingPartner {
        companyId
        companyName
+       municipalityId
+       isMunicipality
      }

Line range hint 165-171: Improve mutation error handling

The current error handling suppresses all runtime errors with a comment. This might hide important errors that should be logged or handled differently.

Consider implementing proper error handling:

const [createSkilavottordAccessControl] = useMutation(
  CreateSkilavottordAccessControlMutation,
  {
    onError(error) {
      // Log the error for debugging while still showing user-friendly message
      console.error('Access control creation failed:', error);
      // The toast message is shown to the user
    },
    refetchQueries: [
      {
        query: SkilavottordAccessControlsQuery,
      },
    ],
  },
)
🧹 Nitpick comments (4)
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (4)

206-213: Simplify error and loading state management

The current implementation combines multiple error and loading states manually. Consider extracting this logic into a custom hook for better maintainability and reusability.

Create a new hook like this:

function useQueryStates(...queries: Array<{ loading?: boolean; error?: Error }>) {
  return {
    loading: queries.some((q) => q.loading),
    error: queries.find((q) => q.error)?.error,
    isData: queries.some((q) => q.data)
  };
}

Then use it like:

const { loading, error, isData } = useQueryStates(
  { loading: recyclingPartnerLoading, error: recyclingPartnerError, data: recyclingPartnerData },
  { loading: accessControlsLoading, error: accessControlsError, data: accessControlsData },
  { loading: recyclingPartnerByIdLoading, error: recyclingPartnerByIdError, data: recyclingPartnerByIdData }
);

235-259: Simplify partner filtering logic

The current implementation has duplicate filtering and mapping logic for both recycling partners and municipalities. This could be simplified using a shared utility function.

Consider refactoring like this:

const createPartnerOptions = (partners: Partner[], isMunicipality: boolean) => 
  filterInternalPartners(partners)
    .filter((partner) => partner.isMunicipality === isMunicipality)
    .map((partner) => ({
      label: isMunicipality ? partner.companyName : 
        (partner.municipalityId ? 
          `${partner.municipalityId} - ${partner.companyName}` : 
          partner.companyName),
      value: partner.companyId,
    }))
    .sort((a, b) => a.label.localeCompare(b.label));

const recyclingPartners = createPartnerOptions(partners, false);
const municipalities = createPartnerOptions(partners, true);

Line range hint 367-471: Extract table rendering into a separate component

The table rendering logic is complex and could be extracted into a separate component for better maintainability and reusability.

Consider creating an AccessControlTable component:

interface AccessControlTableProps {
  loading: boolean;
  error: boolean;
  isData: boolean;
  accessControls: AccessControlType[];
  onEdit: (item: AccessControlType) => void;
  onDelete: (nationalId: string) => void;
  t: typeof t;
  activeLocale: string;
}

const AccessControlTable: FC<AccessControlTableProps> = ({
  loading,
  error,
  isData,
  accessControls,
  onEdit,
  onDelete,
  t,
  activeLocale,
}) => {
  if (loading) return <SkeletonLoader width="100%" height={206} />;
  if (!isData || error) return <Text>{t.empty}</Text>;
  
  return (
    <Table>
      {/* ... existing table code ... */}
    </Table>
  );
};

Line range hint 121-121: Optimize component performance with memoization

The component could benefit from React's memoization features to prevent unnecessary re-renders of complex calculations and child components.

Consider these optimizations:

  1. Memoize the component:
const AccessControl: FC<React.PropsWithChildren<unknown>> = React.memo(() => {
  // ... existing code ...
})
  1. Memoize expensive calculations:
const recyclingPartners = useMemo(() => 
  filterInternalPartners(partners)
    .filter(...)
    .map(...)
    .sort(...),
  [partners]
);
  1. Memoize callback functions:
const handleCreateAccessControl = useCallback(
  async (input: CreateAccessControlInput) => {
    // ... existing code ...
  },
  [createSkilavottordAccessControl]
);
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 04f7ad3 and ddc2114.

📒 Files selected for processing (1)
  • apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (11 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."

@birkirkristmunds birkirkristmunds removed the deploy-feature Deploys features to dev label Dec 27, 2024
- Added missing translations
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
apps/skilavottord/web/i18n/locales/en.json (2)

422-425: Improve consistency in form validation messages.

The validation messages should follow the same pattern. Consider updating the messages to be more descriptive:

-              "required": "ID is required"
+              "required": "Please enter an ID"
-              "required": "Name is required"
+              "required": "Please enter a name"
-              "required": "National ID is required"
+              "required": "Please enter a national ID"
-              "required": "Email is required"
+              "required": "Please enter an email address"

Also applies to: 429-432, 436-439, 444-447


659-674: Consider adding more descriptive success messages.

The success messages could be more informative:

-        "updated": "Updated",
-        "deleted": "Deleted"
+        "updated": "Municipality successfully updated",
+        "deleted": "Municipality successfully deleted"
-        "added": "Added"
+        "added": "Municipality successfully added"
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ddc2114 and d302107.

📒 Files selected for processing (1)
  • apps/skilavottord/web/i18n/locales/en.json (6 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
apps/skilavottord/web/i18n/locales/en.json (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: prepare
🔇 Additional comments (5)
apps/skilavottord/web/i18n/locales/en.json (5)

364-371: LGTM! Table columns are properly defined.

The addition of the "Municipality" column to the recycled cars table aligns with the PR objectives.


375-375: LGTM! Navigation items are properly organized.

The addition of municipality-related navigation items maintains a clear hierarchy in the sidenav.

Also applies to: 378-379


493-496: LGTM! Municipality field is properly defined.

The municipality field in the recycling company form is correctly implemented with appropriate label and placeholder.


594-599: LGTM! Access control municipality field is properly defined.

The municipality field in the access control form maintains consistency with other form fields.


653-657: LGTM! Municipality routes are properly defined.

The routes follow the established pattern for resource management (list, add, edit).

Copy link
Member

@veronikasif veronikasif left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm 💯 (Added some nitpick comments)

@veronikasif veronikasif removed the deprecated:automerge (Disabled) Merge this PR as soon as all checks pass label Jan 9, 2025
@birkirkristmunds birkirkristmunds added the deprecated:automerge (Disabled) Merge this PR as soon as all checks pass label Jan 9, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)

Line range hint 1-35: Consider organizing imports for better maintainability

Group related imports together for better code organization:

  1. External libraries (React, Apollo, etc.)
  2. UI components (@island.is/island-ui/core)
  3. Internal utilities and types
  4. Contexts and GraphQL schemas
 import * as kennitala from 'kennitala'
 import React, { BaseSyntheticEvent, FC, useContext } from 'react'
 import { Control, Controller, FieldError } from 'react-hook-form'
 import { FieldValues } from 'react-hook-form/dist/types'
 import { DeepMap } from 'react-hook-form/dist/types/utils'
+import { gql, useQuery } from '@apollo/client'
 
-import { gql, useQuery } from '@apollo/client'
 import {
   Box,
   Button,
   Checkbox,
   GridColumn,
   GridContainer,
   GridRow,
   Select,
   Stack,
 } from '@island.is/island-ui/core'
+
 import { InputController } from '@island.is/shared/form-fields'
-import {
-  hasDeveloperRole,
-  hasMunicipalityRole,
-} from '@island.is/skilavottord-web/auth/utils'
-import UserContext from '@island.is/skilavottord-web/context/UserContext'
-import { Query } from '@island.is/skilavottord-web/graphql/schema'
 import { useI18n } from '@island.is/skilavottord-web/i18n'
+import { hasDeveloperRole, hasMunicipalityRole } from '@island.is/skilavottord-web/auth/utils'
+import { Query } from '@island.is/skilavottord-web/graphql/schema'
+import UserContext from '@island.is/skilavottord-web/context/UserContext'
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (1)

69-77: Add type safety improvements to form setup.

Consider adding TypeScript interface for the form data structure to improve type safety and maintainability.

interface RecyclingCompanyFormData {
  companyId: string
  companyName: string
  nationalId: string
  email: string
  address: string
  postnumber: string
  city: string
  website: string
  phone: string
  active: boolean
  municipalityId: string
  isMunicipality: boolean
}

const {
  control,
  reset,
  handleSubmit,
  setValue,
  formState: { errors },
} = useForm<RecyclingCompanyFormData>({
  mode: 'onChange',
})

Also applies to: 129-131

apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx (2)

67-82: Consider extracting initial state logic.

The state management and effect hook are well implemented. Consider extracting the initial state logic into a separate utility function for better reusability and testability.

+const getInitialState = (currentPartner?: AccessControl) => ({
+  showCompanies: !currentPartner || currentPartner.role !== AccessControlRole.municipality,
+  showMunicipalities: currentPartner?.role === AccessControlRole.municipality
+})

 useEffect(() => {
-  if (
-    currentPartner &&
-    currentPartner.role === AccessControlRole.municipality
-  ) {
-    setShowCompaniesSelection(false)
-    setShowMunicipalitiesSelection(true)
-  } else {
-    setShowCompaniesSelection(true)
-    setShowMunicipalitiesSelection(false)
-  }
+  const { showCompanies, showMunicipalities } = getInitialState(currentPartner)
+  setShowCompaniesSelection(showCompanies)
+  setShowMunicipalitiesSelection(showMunicipalities)
 }, [currentPartner])

84-102: Simplify role change handler logic and fix typo.

The role change handler has complex nested conditions that could be simplified. Also, there's a typo in the comment ("muncipality").

-// If the user selects municipality we don't need to select a recycling partner since muncipality can't be a recycling partner worker
+// If the user selects municipality we don't need to select a recycling partner since municipality can't be a recycling partner worker
 const handleRoleOnChange = (e: Option) => {
-  if (hasMunicipalityRole(user?.role)) {
-    if (e && e.value === Role.municipality) {
-      setShowCompaniesSelection(false)
-    } else {
-      setShowCompaniesSelection(true)
-    }
-    setShowMunicipalitiesSelection(false)
-  } else if (hasRecyclingFundRole(user?.role)) {
-    if (e && e.value === Role.municipality) {
-      setShowCompaniesSelection(false)
-      setShowMunicipalitiesSelection(true)
-    } else {
-      setShowMunicipalitiesSelection(false)
-      setShowCompaniesSelection(true)
-    }
-  }
+  const isMunicipalityRole = e?.value === Role.municipality
+  const showMunicipalities = hasRecyclingFundRole(user?.role) && isMunicipalityRole
+  const showCompanies = !isMunicipalityRole
+  
+  setShowCompaniesSelection(showCompanies)
+  setShowMunicipalitiesSelection(showMunicipalities)
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d302107 and e4395d9.

📒 Files selected for processing (5)
  • apps/skilavottord/web/auth/utils.ts (1 hunks)
  • apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx (4 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (7 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (5 hunks)
  • apps/skilavottord/ws/src/app/modules/accessControl/accessControl.service.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/skilavottord/ws/src/app/modules/accessControl/accessControl.service.ts
  • apps/skilavottord/web/auth/utils.ts
🧰 Additional context used
📓 Path-based instructions (3)
apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
📓 Learnings (1)
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)
Learnt from: birkirkristmunds
PR: island-is/island.is#17109
File: apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx:336-360
Timestamp: 2024-12-10T15:10:49.998Z
Learning: In the `RecyclingCompanyForm` component (`apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx`), the `isMunicipality` checkbox must remain in the DOM for all users since its value is stored in the database. However, only users with the developer role can manipulate it through the UI. This ensures that the checkbox value is maintained correctly while restricting interaction to authorized users.
🪛 Biome (1.9.4)
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx

[error] 161-161: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

🔇 Additional comments (7)
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (3)

286-320: Municipality selection implementation looks good!

The implementation correctly:

  • Conditionally renders based on isMunicipalityPage
  • Uses isCreatable for selection clearing
  • Disables the field for municipality role users

345-370: Developer-only municipality checkbox implementation is correct

The implementation aligns with the requirements:

  • Checkbox remains in DOM for all users
  • Only developers can interact with it via UI
  • Uses CSS display property for visibility control

384-385: Button changes improve user experience

The use of the save icon and "confirm" text better represents the action being performed.

apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (3)

15-19: LGTM! Well-organized imports and proper GraphQL schema updates.

The changes properly integrate municipality-related functionality by adding necessary imports and updating GraphQL queries with the municipalityId field.

Also applies to: 25-28, 43-43, 63-63


152-157: LGTM! Clean navigation logic implementation.

The navigation logic has been properly refactored into a reusable function, improving code maintainability.

Also applies to: 179-181


184-184: Verify accessibility of new components.

The new PageHeader component and municipality-specific form view should maintain accessibility standards.

#!/bin/bash
# Search for aria attributes and role definitions in the new components
rg -A 5 'aria-|role=' apps/skilavottord/web/components/PageHeader/PageHeader.tsx
rg -A 5 'aria-|role=' apps/skilavottord/web/components/NavigationLinks/NavigationLinks.tsx

Also applies to: 207-207, 219-219

apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx (1)

Line range hint 1-43: LGTM! Well-structured type definitions and imports.

The new interface properties and imports are properly typed and follow TypeScript best practices.

- Fix  translations
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/skilavottord/web/i18n/locales/is.json (1)

661-677: Enhance municipality management translations.

The municipality management section could benefit from additional translations:

  1. Status indicators (active/inactive)
  2. Table headers for the municipality list view
  3. Action button translations (edit/delete)

Add these translations to enhance the user experience:

  "municipalities": {
    "title": "Sveitarfélög",
    "empty": "Ekkert sveitarfélag fannst",
+   "info": "Upplýsingar um skráð sveitarfélög.",
+   "tableHeaders": {
+     "name": "Nafn",
+     "address": "Heimilisfang",
+     "postnumber": "Póstnúmer",
+     "email": "Netfang",
+     "status": "Staða"
+   },
+   "status": {
+     "active": "Virkt",
+     "inactive": "Óvirkt"
+   },
+   "buttons": {
+     "edit": "Breyta",
+     "delete": "Eyða"
+   },
    "municipality": {
      // ... existing translations ...
    }
  }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e4395d9 and 680b5f9.

📒 Files selected for processing (3)
  • apps/skilavottord/web/i18n/locales/en.json (6 hunks)
  • apps/skilavottord/web/i18n/locales/is.json (6 hunks)
  • apps/skilavottord/web/i18n/locales/locales.spec.ts (0 hunks)
💤 Files with no reviewable changes (1)
  • apps/skilavottord/web/i18n/locales/locales.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/skilavottord/web/i18n/locales/en.json
🧰 Additional context used
📓 Path-based instructions (1)
apps/skilavottord/web/i18n/locales/is.json (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
📓 Learnings (1)
apps/skilavottord/web/i18n/locales/is.json (1)
Learnt from: birkirkristmunds
PR: island-is/island.is#17109
File: apps/skilavottord/web/i18n/locales/is.json:0-0
Timestamp: 2024-12-16T12:38:27.802Z
Learning: In the Skilavottord web application, the form for recycling partners is reused for municipalities. Therefore, specific translations for municipalities' form inputs are not needed in `apps/skilavottord/web/i18n/locales/is.json`.
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: prepare
🔇 Additional comments (7)
apps/skilavottord/web/i18n/locales/is.json (7)

364-371: LGTM! Table headers updated to include municipality column.

The table headers for recycling fund overview have been correctly updated to include the municipality column, maintaining consistency with the new municipality feature.


375-375: LGTM! Navigation structure updated for municipality management.

The sidenav has been properly updated to include municipality-related navigation items, providing access to the new municipality management features.

Also applies to: 378-379


383-383: LGTM! Recycling companies section enhanced with municipality integration.

The recycling companies section has been updated with municipality-related functionality, including the ability to add municipalities.

Also applies to: 402-403


504-504: LGTM! Form button translation added.

The "confirm" button translation has been properly added to support the municipality management workflow.


596-601: LGTM! Access control translations updated for municipality role.

The access control section has been properly updated to include municipality-related fields and validation messages.


655-659: LGTM! Route translations added for municipality management.

The routes section has been updated with the necessary paths for municipality management features.


Line range hint 422-498: Verify translation key consistency in form inputs.

The form input translations follow a consistent pattern, but let's verify that all required fields have proper validation messages.

Run this script to check translation key consistency:

✅ Verification successful

All form input translations are consistent and properly validated

  • All required fields have proper validation messages
  • Special validations are correctly implemented for email format and national ID
  • Field length validation for "Starfstöð" follows a different but valid pattern
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent translation patterns in form inputs
# Look for any form input translations that might be missing validation rules

rg -U "\"inputs\":\s*{\s*[^}]*}" apps/skilavottord/web/i18n/locales/is.json | \
  rg -v "\"rules\":\s*{[^}]*\"required\""

Length of output: 353


Script:

#!/bin/bash
# Check for input fields missing any of the standard keys
echo "=== Checking for missing standard keys ==="
rg -U '"[^"]+"\s*:\s*{(?!.*"label"|.*"placeholder"|.*"rules")' apps/skilavottord/web/i18n/locales/is.json

# Check for input fields missing required validation
echo "=== Checking for missing required validation ==="
rg -U '"rules"\s*:\s*{(?!.*"required")' apps/skilavottord/web/i18n/locales/is.json

# Check email field for proper validation
echo "=== Checking email validation ==="
rg -U '"email"\s*:\s*{.*"rules".*"validate"' apps/skilavottord/web/i18n/locales/is.json

Length of output: 976


Script:

#!/bin/bash
# Simple pattern matching for validation rules
echo "=== All validation rules ==="
rg '"rules"' apps/skilavottord/web/i18n/locales/is.json -A 3

echo "=== Fields with validate message ==="
rg '"validate"' apps/skilavottord/web/i18n/locales/is.json -B 3

Length of output: 3421

- Fix  after code rabbit comment
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)

349-374: Improve developer-only checkbox implementation

While correctly keeping the checkbox in DOM, two improvements could be made:

  1. Replace inline styles with Box's display prop:
-<Box
-  style={{
-    display: user?.role && hasDeveloperRole(user.role) ? 'block' : 'none',
-  }}
->
+<Box
+  display={user?.role && hasDeveloperRole(user.role) ? 'block' : 'none'}
+>
  1. Move the Norwegian label to translation files:
-label="Er sveitarfélag"
+label={t.recyclingCompany.form.inputs.isMunicipality.label}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 680b5f9 and 0dcb452.

📒 Files selected for processing (2)
  • apps/skilavottord/web/i18n/locales/locales.spec.ts (1 hunks)
  • apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/skilavottord/web/i18n/locales/locales.spec.ts
🧰 Additional context used
📓 Path-based instructions (1)
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)

Pattern apps/**/*: "Confirm that the code adheres to the following:

  • NextJS best practices, including file structure, API routes, and static generation methods.
  • Efficient state management and server-side rendering techniques.
  • Optimal use of TypeScript for component and utility type safety."
📓 Learnings (1)
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)
Learnt from: birkirkristmunds
PR: island-is/island.is#17109
File: apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx:336-360
Timestamp: 2024-12-10T15:10:49.998Z
Learning: In the `RecyclingCompanyForm` component (`apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx`), the `isMunicipality` checkbox must remain in the DOM for all users since its value is stored in the database. However, only users with the developer role can manipulate it through the UI. This ensures that the checkbox value is maintained correctly while restricting interaction to authorized users.
🔇 Additional comments (4)
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (4)

Line range hint 1-35: LGTM! Well-organized imports and clean interface update.

The new imports and interface changes are properly structured and typed, following TypeScript best practices.


290-324: LGTM! Municipality selection implementation is correct.

The implementation correctly:

  • Conditionally renders based on isMunicipalityPage
  • Uses isCreatable for selection clearing
  • Makes municipalityId optional as intended
  • Properly disables the field for municipality role users

388-389: LGTM! Improved form submission UX.

The button changes enhance user experience by:

  • Using a more appropriate "save" icon
  • Preventing double submission with loading state
  • Using clearer "confirm" text

38-78: 🛠️ Refactor suggestion

Enhance error handling and loading states

While the data transformation and sorting are well implemented, the error handling could be improved for better user experience.

Consider this enhancement:

 if (error) {
-  console.error('Failed to fetch municipalities:', error)
+  // Show user-friendly error message
+  return (
+    <Box background="red100" padding={3} marginBottom={3}>
+      <Text variant="h5">
+        {t.recyclingCompany.errors.failedToLoadMunicipalities}
+      </Text>
+    </Box>
+  )
 }

+if (loading && !municipalities?.length) {
+  return (
+    <Box padding={3}>
+      <LoadingDots />
+    </Box>
+  )
+}

Likely invalid or redundant comment.

@kodiakhq kodiakhq bot merged commit 98124ef into main Jan 9, 2025
27 checks passed
@kodiakhq kodiakhq bot deleted the feat/skilavottord-add-municipality branch January 9, 2025 16:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
deprecated:automerge (Disabled) Merge this PR as soon as all checks pass
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants